library(synapser)

New synapser version detected: 
    You are using synapser version 0.11.7.
    synapser version 1.0.59 is detected at http://ran.synapse.org.
    To upgrade to the latest version of synapser, please run the following command:
    install.packages("synapser", repos="http://ran.synapse.org")


TERMS OF USE NOTICE:
  When using Synapse, remember that the terms and conditions of use require that you:
  1) Attribute data contributors when discussing these data or results from these data.
  2) Not discriminate, identify, or recontact individuals or groups represented by the data.
  3) Use and contribute only data de-identified to HIPAA standards.
  4) Redistribute data only under these same terms of use.
# library(paxtoolsr)
# library(org.Hs.eg.db)
# library(clusterProfiler)
# library(HotNetvieweR)
library(igraph)

Attaching package: ‘igraph’

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union
library(tidygraph)

Attaching package: ‘tidygraph’

The following object is masked from ‘package:igraph’:

    groups

The following object is masked from ‘package:stats’:

    filter
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.0.6     ✓ dplyr   1.0.4
✓ tidyr   1.1.2     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::as_data_frame() masks tibble::as_data_frame(), igraph::as_data_frame()
x purrr::compose()       masks igraph::compose()
x tidyr::crossing()      masks igraph::crossing()
x dplyr::filter()        masks tidygraph::filter(), stats::filter()
x dplyr::groups()        masks tidygraph::groups(), igraph::groups()
x dplyr::lag()           masks stats::lag()
x purrr::simplify()      masks igraph::simplify()
# source(paste0(here::here(),'/../biodom_tally.R'))
# source(paste0(here::here(),'/../biodom_enr.R'))
# source(paste0(here::here(),'/../biodom_enr_plots.R'))

theme_set(theme_bw())

Gather data

Grab relevant data from synapse, including:
1) Target Risk Scores (syn25575156) and Omics Scores (syn22758536)
2) Biodomain Definitions (syn25428992)
3) Pathway Commons Full Graph, v12 (syn51080932)
4) Human Protein Atlas tissue immunohistochemistry micro array data (syn51074598)
5) RNA Brain GTEx (syn51074639)
6) AMP-AD cohort pairwise partial correlations (ROSMAP, Mayo, MSBB); these are quite large! (> 6 GB), wait to load until performing this analysis
7) SEA-AD single cell data (syn51441105)

synLogin()
Welcome, Greg Cary!NULL
# target risk scores
scores <- read_csv(synTableQuery('select * from syn25575156', 
                                 includeRowIdAndRowVersion = F)$filepath)
omics <- read_csv(synTableQuery('select * from syn22758536', 
                                includeRowIdAndRowVersion = F)$filepath)

Extract the core NW tables

net.tbl <- igraph::as_data_frame(net)

v.attr <- tibble( na = vertex.attributes(net) ) %>%
  t() %>% as_tibble(rownames = NA, .name_repair = 'unique') %>% unnest(everything()) %>%
  rename_with(., ~names(vertex.attributes(net)), everything())

e.attr <- tibble( ea = edge.attributes(net) ) %>% 
  t() %>% as_tibble(rownames = NA, .name_repair = 'unique') %>% unnest(everything()) %>% 
  rename_with(., ~names(edge.attributes(net)), everything())

NODE: Human Protein Atlas

Specify brain tissue types

brain.tissues <- c(
 "caudate", "cerebellum", "cerebral cortex", "hippocampus", 
 "hypothalamus", "pituitary gland", "dorsal raphe", 
 "choroid plexus", "substantia nigra"
)

brain.genes <- tissue.array %>% filter(
  Tissue %in% brain.tissues, 
  Level %in% c('Low','Medium','High','Ascending','Descending'),
  Reliability %in% c('Enhanced','Supported','Approved')
) %>% pull(Gene.name) %>% unique()

not.brain <- tissue.array %>% filter(
  Tissue %in% brain.tissues,
  Level %in% c('Not detected'),
  Reliability %in% c('Enhanced','Supported','Approved')
) %>% pull(Gene.name) %>% unique()
# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

brain.gtex %>% 
  mutate(hpa = case_when(Gene.name %in% brain.genes ~ 
                           paste0('brain (n = ', length(intersect(Gene.name, brain.genes)),' genes)'),
                         Gene.name %in% not.brain ~ 
                           paste0('not brain (n = ', length(intersect(Gene.name,not.brain)),' genes)'),
                         T ~ NA_character_)) %>% 
  filter(!is.na(hpa)) %>% 
  ggplot(aes( log10(nTPM), fill = hpa))+
  geom_density(aes(color = hpa), alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  theme(legend.position = 'top')

# also "brain genes":
tad.deg <- scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

brain.gtex %>% 
  mutate(hpa = case_when(Gene.name %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(Gene.name,tad.deg)),' genes)'),
                         T ~ paste0('not TAD DEG (n = ', length(setdiff(Gene.name, tad.deg)),' genes)'),
                         )) %>% 
  filter(!is.na(hpa)) %>% 
  ggplot(aes( log10(nTPM), fill = hpa))+
  geom_density(aes(color = hpa), alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  theme(legend.position = 'top')

# also "brain genes":
tad.deg <- scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

brain.gtex %>% 
  mutate(
  hpa = case_when(
    Gene.name %in% brain.genes ~ 
      paste0('HPA brain (n = ', length(intersect(Gene.name, brain.genes)),' genes)'),
    Gene.name %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(Gene.name,tad.deg)),' genes)'),
    Gene.name %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(Gene.name,not.brain)),' genes)'),
    T ~ paste0('other (n = ', length(setdiff(Gene.name, union(union(brain.genes, tad.deg), not.brain))) ,' genes)')
    )) %>% 
  ggplot(aes( log10(nTPM), fill = hpa))+
  geom_density(aes(color = hpa), alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  theme(legend.position = 'top')

NODE: SEA-AD single cell data

subclass

both dimensions

t = .9

tmp = seaad.broad %>% 

  # filter(gene %in% not.brain) %>% 
  # mutate(hpa = 'not') %>% 

  mutate(
      hpa = case_when(
          gene %in% brain.genes ~ 'brain',
          gene %in% not.brain ~ 'not',
          gene %in% tad.deg ~ 'deg',
          T ~ 'other'
      )
  ) %>%

  group_by(cellType, hpa) %>% 
  summarise( 
    exp = quantile(upperQ_exp, t), 
    fxn = quantile(fxn_exp, t)
    ) 
`summarise()` has grouped output by 'cellType'. You can override using the `.groups` argument.
# bind_rows(
#     tmp, 
#     tmp %>% filter(hpa == 'not') %>% mutate(exp = exp + .142, fxn = fxn + .142, hpa = 'new')
#   ) %>% 
tmp %>% 
  ggplot(aes(fxn, exp, group = hpa))+
  geom_smooth(method = 'lm', color = 'grey20', lwd = .5, lty = 2)+
  # geom_abline(intercept = 1.5294, slope = -2.562569)+
  geom_abline(intercept = 2.3, slope = -2.5)+
  annotate(geom = 'text', x = .65, y = 0, label = 'y = -2.5x + 2.3', hjust = 0)+
  geom_point(aes(color = cellType, shape = hpa), size = 2, alpha = .5)+
  labs(y = 'quantile expression', x = 'quantile fraction expressing',
       subtitle = paste0('plotting quantile: ', t))

t = .9

seaad.broad %>% 
  
  # filter(gene %in% not.brain) %>% 
  # mutate(hpa = 'not') %>% 

  mutate(
      hpa = case_when(
          gene %in% brain.genes ~ 'brain',
          gene %in% not.brain ~ 'not',
          gene %in% tad.deg ~ 'deg',
          T ~ 'other'
      )
  ) %>%
  filter(hpa == 'not') %>%

  group_by(cellType, hpa) %>%
  summarise( exp = quantile(upperQ_exp, t), 
             fxn = quantile(fxn_exp, t)
             ) %>% 
  lm(exp~fxn, data = .) %>% 
  broom::tidy()
`summarise()` has grouped output by 'cellType'. You can override using the `.groups` argument.
x = map_dfr(
    seq(1.5,3.5,.01),
    ~{
        seaad.broad %>% 
            filter( upperQ_exp >= -2.5 * fxn_exp + .x) %>% 
            summarise(
                int = .x,
                n.brain = length(intersect(gene, brain.genes )),
                n.not = length(intersect(gene,not.brain)),
                n.deg = length(intersect(gene,tad.deg)),
                n.other = length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))),
                diff.b = (n.brain - n.not),
                pct.b = 100*(diff.b/n.brain),
                diff.d = n.deg - n.not,
                pct.d = 100*(diff.d/n.brain)
            )
    }
) %>% 
  arrange(desc(diff.b), desc(pct.d));

qplot(x$int, x$diff.b, geom = 'line')


DT::datatable(x)
t = .9

thresh = seaad.broad %>% 
  filter(gene %in% not.brain) %>%
  group_by(broad, cellType) %>%
  summarise( 
    exp1 = quantile(upperQ_exp, t),
    fxn1 = quantile(fxn_exp, t)
  ) %>% 
  mutate(
    exp = exp1+.142,
    fxn = fxn1+.142,
    hpa = 'new.dat'
  ) 
`summarise()` has grouped output by 'broad'. You can override using the `.groups` argument.
seaad.broad %>% 

  mutate(
    hpa = case_when(
        gene %in% brain.genes ~ 'brain',
        gene %in% not.brain ~ 'not',
        gene %in% tad.deg ~ 'deg',
        T ~ 'other')
      ) %>% 
  ggplot(aes(fxn_exp, upperQ_exp, group = hpa))+
  geom_abline(intercept = 2.25, slope = -2.5)+
  # annotate(geom = 'text', x = .65, y = 0, label = 'y = -2.5x + 2.5', hjust = 0)+
  geom_point(data = thresh, aes(x = fxn, y = exp), size = 2, alpha = .5)+
  geom_smooth(method = 'lm', aes(color = hpa), lwd = .5, lty = 2)+
  labs(y = 'expression', x = 'fraction expressing'
       #, subtitle = paste0('plotting quantile: ', t)
       )+
  facet_wrap(~broad, scales = 'free')

t = .9

thresh = seaad.broad %>% 
  filter(gene %in% not.brain) %>%
  group_by(broad, cellType) %>%
  summarise( 
    exp1 = quantile(upperQ_exp, t),
    fxn1 = quantile(fxn_exp, t)
  ) %>% 
  mutate(
    exp = exp1+.142,
    fxn = fxn1+.142,
    hpa = 'new.dat'
  ) 
`summarise()` has grouped output by 'broad'. You can override using the `.groups` argument.
seaad.broad %>% 
  mutate(
    hpa = case_when(
        gene %in% brain.genes ~ 'brain',
        gene %in% not.brain ~ 'not',
        gene %in% tad.deg ~ 'deg',
        T ~ 'other')
      ) %>% 

  # group_by(cellType) %>%
  # filter(
  #   fxn_exp >= thresh$fxn[ which(thresh$cellType == cellType) ] %>% unique(),
  #   upperQ_exp >= thresh$exp[ which(thresh$cellType == cellType) ] %>% unique(),
  #   .preserve = T
  # ) %>%
  # ungroup() %>%
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%

  ggplot(aes(fxn_exp, upperQ_exp, group = hpa))+
  geom_abline(intercept = 2.3, slope = -2.5)+
  # annotate(geom = 'text', x = .65, y = 0, label = 'y = -2.5x + 2.5', hjust = 0)+
  geom_point(data = thresh, aes(x = fxn, y = exp), size = 2, alpha = .5)+
  geom_smooth(method = 'lm', aes(color = hpa), lwd = .5, lty = 2)+
  labs(y = 'expression', x = 'fraction expressing'
       #, subtitle = paste0('plotting quantile: ', t)
       )+
  facet_wrap(~broad, scales = 'free')

seaad.broad %>% 
  ggplot(aes(upperQ_exp, fxn_exp))+ 
  geom_bin2d(aes(fill = ..count.. ))+
  viridis::scale_fill_viridis(trans = 'log10', option = 'A')+
  ggtitle('no filter')+
  facet_wrap(~broad)

thresh = seaad.broad %>% 
  filter(gene %in% not.brain) %>%
  group_by(broad, cellType) %>%
  summarise( 
    exp1 = quantile(upperQ_exp, t),
    fxn1 = quantile(fxn_exp, t)
  ) %>% 
  mutate(
    exp = exp1+.142,
    fxn = fxn1+.142,
    hpa = 'new.dat'
  ) 
`summarise()` has grouped output by 'broad'. You can override using the `.groups` argument.
seaad.broad %>% 
  mutate(
    hpa = case_when(
        gene %in% brain.genes ~ 'brain',
        gene %in% tad.deg ~ 'deg',
        gene %in% not.brain ~ 'not',
        T ~ 'other')
      ) %>% 
  filter(!is.na(hpa)) %>%     

  # group_by(cellType) %>%
  # filter(
  #   fxn_exp >= thresh$fxn[ which(thresh$cellType == cellType) ] %>% unique(),
  #   upperQ_exp >= thresh$exp[ which(thresh$cellType == cellType) ] %>% unique(),
  #   .preserve = T
  # ) %>%
  # ungroup() %>%

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%

  # group_by(cellType, hpa) %>% 
  # mutate( exp = quantile(upperQ_exp, .9), 
  #         fxn = quantile(fxn_exp, .9)
  #         ) %>% 
  # group_by(cellType) %>%
  # filter(  ) %>%
  # ungroup() %>% 
  
  mutate(
    n = case_when(
      gene %in% brain.genes ~ length(intersect(gene, brain.genes)),
      gene %in% tad.deg ~ length(intersect(gene,tad.deg)),
      gene %in% not.brain ~ length(intersect(gene,not.brain)),
      T ~ length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain))))
      )) %>%
  ggplot(aes(upperQ_exp, fxn_exp))+ 
  geom_bin2d(aes(fill = ..count.. ))+
  viridis::scale_fill_viridis(trans = 'log10', option = 'A')+
  facet_wrap(~broad)


seaad.broad %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 
  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  ggplot(aes(upperQ_exp, fxn_exp))+ 
  geom_bin2d(aes(fill = ..count.. ))+
  viridis::scale_fill_viridis(trans = 'log10', option = 'A')+
  ggtitle('no filter')+
  facet_grid(broad~hpa1)

NA

thresh = seaad.broad %>% 
  filter(gene %in% not.brain) %>%
  group_by(broad, cellType) %>%
  summarise( 
    exp1 = quantile(upperQ_exp, t),
    fxn1 = quantile(fxn_exp, t)
  ) %>% 
  mutate(
    exp = exp1+.142,
    fxn = fxn1+.142,
    hpa = 'new.dat'
  ) 
`summarise()` has grouped output by 'broad'. You can override using the `.groups` argument.
seaad.broad %>% 
  mutate(
    hpa = case_when(
        gene %in% brain.genes ~ 'brain',
        gene %in% tad.deg ~ 'tad.deg',
        gene %in% not.brain ~ 'not.brain',
        T ~ 'other')
      ) %>% 
  filter(!is.na(hpa)) %>%     

  # group_by(cellType) %>%
  # filter(
  #   fxn_exp >= thresh$fxn[ which(thresh$cellType == cellType) ] %>% unique(),
  #   upperQ_exp >= thresh$exp[ which(thresh$cellType == cellType) ] %>% unique(),
  #   .preserve = T
  # ) %>%
  # ungroup() %>%
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  # group_by(cellType, hpa) %>%
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>%
  # group_by(cellType) %>%
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>%
  # ungroup() %>%
  
  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  ggplot(aes(upperQ_exp, fxn_exp))+ 
  geom_bin2d(aes(fill = ..count.. ))+
  viridis::scale_fill_viridis(trans = 'log10', option = 'A')+
  ggtitle('filtered')+
  facet_grid(broad~hpa1)

NA

fxn expressed

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad.broad %>% 
  # filter(is.na(group)) %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  filter(!is.na(hpa)) %>% 
  ggplot(aes( fxn_exp, fill = hpa))+
  geom_density(aes(color = hpa), alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,.25), ylim = c(0,5))+
  theme(legend.position = 'top')

# seaad.broad %>% group_by(cellType) %>% summarise(mn = median(fraction_expressed))

seaad.broad %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  group_by(cellType, hpa) %>% 
  mutate(top_exp = quantile(upperQ_exp, 0.75),
         top_fxn = quantile(fxn_exp, 0.75)) %>% 
  ggplot(., aes(fxn_exp, cellType, fill = hpa)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5)) +
  geom_point(aes(x = top_fxn, color = hpa))+
  # stat_summary(fun = function(x) quantile(x,0.5), geom="point", size=2, color="red", position = 'dodge')+
  # ggforce::facet_zoom(xlim = c(0,0.08), horizontal = F)
  coord_cartesian(xlim = c(0,0.25))

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad.broad %>% 
  # filter(is.na(group)) %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  filter(!is.na(hpa)) %>% 
  ggplot(aes( fxn_exp, fill = hpa))+
  # geom_density(aes(color = hpa), alpha = .1)+
  geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,.25), ylim = c(0,1e5))+
  theme(legend.position = 'top')

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad.broad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  
  ggplot(aes( fxn_exp, fill = hpa1))+
  # geom_density(aes(color = hpa1), alpha = .1)+
  geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,.25), ylim = c(0,1e5))+
  theme(legend.position = 'top')

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad.broad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  
  ggplot(aes( fxn_exp, color = hpa1))+
  geom_density( alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  geom_vline(xintercept = 0.2, lty = 2)+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,.25), ylim = c(0,1.7))+#
  theme(legend.position = 'top')

# seaad.broad %>% group_by(cellType) %>% summarise(mn = median(fraction_expressed))

seaad.broad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 

  ggplot(., aes(fxn_exp, cellType, fill = hpa1)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5), trim = F) +
  # geom_point(aes(x = top_fxn, color = hpa))+
  # stat_summary(fun = function(x) quantile(x,0.5), geom="point", size=2, color="red", position = 'dodge')+
  # ggforce::facet_zoom(xlim = c(0,0.08), horizontal = F)
  coord_cartesian(xlim = c(0,1))

avg expression

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad.broad %>% 
  # filter(is.na(group)) %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  filter(!is.na(hpa)) %>% 
  ggplot(aes( (upperQ_exp), fill = hpa))+
  geom_density(aes(color = hpa), alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,2), ylim = c(0,1.3) )+
  theme(legend.position = 'top')

# seaad.broad %>% group_by(cellType) %>% summarise(mn = median(fraction_expressed))

seaad.broad %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  group_by(cellType, hpa) %>% 
  mutate(top_exp = quantile(upperQ_exp, 0.75),
         top_fxn = quantile(fxn_exp, 0.75)) %>% 
  ggplot(., aes(upperQ_exp, cellType, fill = hpa)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5)) +
  # geom_point(aes(x = top_exp, color = hpa))+
  # stat_summary(fun = function(x) quantile(x,0.5), geom="point", size=2, color="red", position = 'dodge')+
  # ggforce::facet_zoom(xlim = c(0,0.08), horizontal = F)
  coord_cartesian(xlim = c(0,6))

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad.broad %>% 
  # filter(is.na(group)) %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  # group_by(cellType, hpa) %>% 
  # mutate(md_exp = quantile(upperQ_exp, 0.5),
  #        fivepct_exp = quantile(upperQ_exp, 0.95), 
  #        fivepct_fxn = quantile(fxn_exp, .5)) %>% 
  filter(!is.na(hpa)) %>% 
  ggplot(aes( (upperQ_exp), fill = hpa))+
  # geom_density(aes(color = hpa), alpha = .1)+
  geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,2), ylim = c(0,3.5e4) )+
  theme(legend.position = 'top')

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad.broad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  
  ggplot(aes( upperQ_exp, fill = hpa1))+
  # geom_density(aes(color = hpa), alpha = .1)+
  geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,2), ylim = c(0,3.5e4) )+
  theme(legend.position = 'top')

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad.broad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 

  ggplot(aes( upperQ_exp, color = hpa1 ))+
  geom_density( alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(color = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,2), ylim = c(0,1.3) )+
  theme(legend.position = 'top')

# seaad.broad %>% group_by(cellType) %>% summarise(mn = median(fraction_expressed))

seaad.broad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  
  ggplot(., aes(upperQ_exp, cellType, fill = hpa1)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5), trim = F) +
  # geom_point(aes(x = top_exp, color = hpa))+
  # stat_summary(fun = function(x) quantile(x,0.5), geom="point", size=2, color="red", position = 'dodge')+
  # ggforce::facet_zoom(xlim = c(0,0.08), horizontal = F)
  coord_cartesian(xlim = c(0,6))

celltype-specific genes

# McKenzie brain cell type specfic expression PMID 29892006
url='https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5995803/bin/41598_2018_27293_MOESM2_ESM.xlsx'
httr::GET(url, httr::write_disk(tf <- tempfile(fileext = ".xlsx")))
Response [https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5995803/bin/41598_2018_27293_MOESM2_ESM.xlsx]
  Date: 2023-06-02 16:20
  Status: 200
  Content-Type: application/octet-stream
  Size: 3.23 MB
<ON DISK>  /tmp/RtmpiSkVJg/file3f71186c6bc9.xlsx
# readxl::excel_sheets(tf)
# [1] "top_all_enrich"        "top_human_enrich"      "top_mouse_enrich"     
# [4] "top_all_expression"    "top_human_expression"  "top_mouse_expression" 
# [7] "top_all_specificity"   "top_human_specificity" "top_mouse_specificity"

ct_spec = readxl::read_xlsx(tf,sheet = 'top_all_enrich', skip = 1)

ct_spec %>% 
  group_by(Celltype) %>% 
  summarise(mn = median(grand_mean), sd = sd(grand_mean), mn_sd = mn+sd) %>% 
  arrange(desc(mn_sd))

dups = ct_spec$gene[which(duplicated(ct_spec$gene))] %>% unique() 
ct_spec %>% 
  filter(!(gene %in% dups)) %>% 
  group_by(Celltype) %>% 
  mutate(mn = median(grand_mean), sd = sd(grand_mean), mn_sd = mn+sd) %>% 
  ggplot(aes(grand_mean, color = Celltype))+
  geom_density()+
  geom_vline(aes(xintercept = mn_sd, color = Celltype))

# seaad.broad = read_csv('/projects/carter-lab/caryg/seaAD/data/seaAD_broad_summaryCounts.csv')
# seaad.broad = read_csv('/projects/carter-lab/caryg/seaAD/data/seaAD_broad_upperQ_summaryCounts.csv')

ct_spec %>% 
  filter(!(gene %in% dups)) %>% 
  group_by(Celltype) %>% 
  mutate(mn = median(grand_mean), sd = sd(grand_mean), mn_sd = mn+sd) %>% 
  filter(grand_mean > mn_sd) %>% 
  select(gene, Celltype) %>% 
  distinct() %>% 
  inner_join(seaad.broad, ., by = 'gene') %>% 

  # filter( upperQ_exp >= -2.5 * fxn_exp + 2.5) %>%

  ggplot(., aes(broad, upperQ_exp, fill = Celltype)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5), trim = F) 

# seaad.broad = read_csv('/projects/carter-lab/caryg/seaAD/data/seaAD_broad_summaryCounts.csv')
# seaad.broad = read_csv('/projects/carter-lab/caryg/seaAD/data/seaAD_broad_upperQ_summaryCounts.csv')

ct_spec %>% 
  filter(!(gene %in% dups)) %>% 
  group_by(Celltype) %>% 
  mutate(mn = median(grand_mean), sd = sd(grand_mean), mn_sd = mn+sd) %>% 
  filter(grand_mean > mn_sd) %>% 
  select(gene, Celltype) %>% 
  distinct() %>% 
  inner_join(seaad.broad, ., by = 'gene') %>% 

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%

  ggplot(., aes(broad, upperQ_exp, fill = Celltype)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5), trim = F) 

supertype

seaad = read_csv('/projects/carter-lab/caryg/seaAD/data/seaAD_upperQ_summaryCounts.csv')

── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────
cols(
  broad = col_character(),
  cellType = col_character(),
  group = col_character(),
  gene = col_character(),
  fxn_exp = col_double(),
  upperQ_exp = col_double()
)

both dimensions

t = .9

seaad %>% 
  
  # filter(gene %in% not.brain) %>% 
  # mutate(hpa = 'not') %>% 

  mutate(
      hpa = case_when(
          gene %in% brain.genes ~ 'brain',
          gene %in% not.brain ~ 'not',
          gene %in% tad.deg ~ 'deg',
          T ~ 'other'
      )
  ) %>%
  filter(hpa == 'not') %>%

  group_by(cellType, hpa) %>%
  summarise( exp = quantile(upperQ_exp, t), 
             fxn = quantile(fxn_exp, t)
             ) %>% 
  lm(exp~fxn, data = .) %>% 
  broom::tidy()
`summarise()` has grouped output by 'cellType'. You can override using the `.groups` argument.
x = map_dfr(
    seq(1.5,3,.1),
    ~{
        seaad %>% 
            filter( upperQ_exp >= -2.5 * fxn_exp + .x) %>% 
            summarise(
                int = .x,
                n.brain = length(intersect(gene, brain.genes )),
                n.not = length(intersect(gene,not.brain)),
                n.deg = length(intersect(gene,tad.deg)),
                n.other = length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))),
                diff.b = (n.brain - n.not),
                pct.b = 100*(diff.b/n.brain),
                diff.d = n.deg - n.not,
                pct.d = 100*(diff.d/n.brain)
            )
    }
) %>% 
  arrange(desc(diff.b), desc(pct.d));

qplot(x$int, x$diff.b, geom = 'line')


DT::datatable(x)
t = .9

thresh = seaad %>% 
  filter(gene %in% not.brain) %>%
  group_by(broad, cellType) %>%
  summarise( 
    exp1 = quantile(upperQ_exp, t),
    fxn1 = quantile(fxn_exp, t)
  ) %>% 
  mutate(
    exp = exp1+.142,
    fxn = fxn1+.142,
    hpa = 'new.dat'
  ) 
`summarise()` has grouped output by 'broad'. You can override using the `.groups` argument.
seaad %>% 

  mutate(
    hpa = case_when(
        gene %in% brain.genes ~ 'brain',
        gene %in% not.brain ~ 'not',
        gene %in% tad.deg ~ 'deg',
        T ~ 'other')
      ) %>% 
  ggplot(aes(fxn_exp, upperQ_exp, group = hpa))+
  geom_abline(intercept = 2.3, slope = -2.5)+
  # annotate(geom = 'text', x = .65, y = 0, label = 'y = -2.5x + 2.5', hjust = 0)+
  geom_point(data = thresh, aes(x = fxn, y = exp), size = 2, alpha = .5)+
  geom_smooth(method = 'lm', aes(color = hpa), lwd = .5, lty = 2)+
  labs(y = 'expression', x = 'fraction expressing'
       #, subtitle = paste0('plotting quantile: ', t)
       )+
  facet_wrap(~broad, scales = 'free')

t = .9

thresh = seaad %>% 
  filter(gene %in% not.brain) %>%
  group_by(broad, cellType) %>%
  summarise( 
    exp1 = quantile(upperQ_exp, t),
    fxn1 = quantile(fxn_exp, t)
  ) %>% 
  mutate(
    exp = exp1+.142,
    fxn = fxn1+.142,
    hpa = 'new.dat'
  ) 
`summarise()` has grouped output by 'broad'. You can override using the `.groups` argument.
seaad %>% 
  mutate(
    hpa = case_when(
        gene %in% brain.genes ~ 'brain',
        gene %in% not.brain ~ 'not',
        gene %in% tad.deg ~ 'deg',
        T ~ 'other')
      ) %>% 

  # group_by(cellType) %>%
  # filter(
  #   fxn_exp >= thresh$fxn[ which(thresh$cellType == cellType) ] %>% unique(),
  #   upperQ_exp >= thresh$exp[ which(thresh$cellType == cellType) ] %>% unique(),
  #   .preserve = T
  # ) %>%
  # ungroup() %>%
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%

  ggplot(aes(fxn_exp, upperQ_exp, group = hpa))+
  geom_abline(intercept = 2.3, slope = -2.5)+
  # annotate(geom = 'text', x = .65, y = 0, label = 'y = -2.5x + 2.5', hjust = 0)+
  geom_point(data = thresh, aes(x = fxn, y = exp), size = 2, alpha = .5)+
  geom_smooth(method = 'lm', aes(color = hpa), lwd = .5, lty = 2)+
  labs(y = 'expression', x = 'fraction expressing'
       #, subtitle = paste0('plotting quantile: ', t)
       )+
  facet_wrap(~broad, scales = 'free')

seaad %>% 
  ggplot(aes(upperQ_exp, fxn_exp))+ 
  geom_bin2d(aes(fill = ..count.. ))+
  viridis::scale_fill_viridis(trans = 'log10', option = 'A')+
  ggtitle('no filter')+
  facet_wrap(~broad)

thresh = seaad %>% 
  filter(gene %in% not.brain) %>%
  group_by(broad, cellType) %>%
  summarise( 
    exp1 = quantile(upperQ_exp, t),
    fxn1 = quantile(fxn_exp, t)
  ) %>% 
  mutate(
    exp = exp1+.142,
    fxn = fxn1+.142,
    hpa = 'new.dat'
  ) 
`summarise()` has grouped output by 'broad'. You can override using the `.groups` argument.
seaad %>% 
  mutate(
    hpa = case_when(
        gene %in% brain.genes ~ 'brain',
        gene %in% tad.deg ~ 'deg',
        gene %in% not.brain ~ 'not',
        T ~ 'other')
      ) %>% 
  filter(!is.na(hpa)) %>%     

  # group_by(cellType) %>%
  # filter(
  #   fxn_exp >= thresh$fxn[ which(thresh$cellType == cellType) ] %>% unique(),
  #   upperQ_exp >= thresh$exp[ which(thresh$cellType == cellType) ] %>% unique(),
  #   .preserve = T
  # ) %>%
  # ungroup() %>%

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%

  # group_by(cellType, hpa) %>% 
  # mutate( exp = quantile(upperQ_exp, .9), 
  #         fxn = quantile(fxn_exp, .9)
  #         ) %>% 
  # group_by(cellType) %>%
  # filter(  ) %>%
  # ungroup() %>% 
  
  ggplot(aes(upperQ_exp, fxn_exp))+ 
  geom_bin2d(aes(fill = ..count.. ))+
  viridis::scale_fill_viridis(trans = 'log10', option = 'A')+
  facet_wrap(~broad)


seaad %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 
  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  ggplot(aes(upperQ_exp, fxn_exp))+ 
  geom_bin2d(aes(fill = ..count.. ))+
  viridis::scale_fill_viridis(trans = 'log10', option = 'A')+
  ggtitle('no filter')+
  facet_grid(broad~hpa1)

NA

thresh = seaad %>% 
  filter(gene %in% not.brain) %>%
  group_by(broad, cellType) %>%
  summarise( 
    exp1 = quantile(upperQ_exp, t),
    fxn1 = quantile(fxn_exp, t)
  ) %>% 
  mutate(
    exp = exp1+.142,
    fxn = fxn1+.142,
    hpa = 'new.dat'
  ) 
`summarise()` has grouped output by 'broad'. You can override using the `.groups` argument.
seaad %>% 
  mutate(
    hpa = case_when(
        gene %in% brain.genes ~ 'brain',
        gene %in% tad.deg ~ 'tad.deg',
        gene %in% not.brain ~ 'not.brain',
        T ~ 'other')
      ) %>% 
  filter(!is.na(hpa)) %>%     

  # group_by(cellType) %>%
  # filter(
  #   fxn_exp >= thresh$fxn[ which(thresh$cellType == cellType) ] %>% unique(),
  #   upperQ_exp >= thresh$exp[ which(thresh$cellType == cellType) ] %>% unique(),
  #   .preserve = T
  # ) %>%
  # ungroup() %>%
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  # group_by(cellType, hpa) %>%
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>%
  # group_by(cellType) %>%
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>%
  # ungroup() %>%
  
  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  ggplot(aes(upperQ_exp, fxn_exp))+ 
  geom_bin2d(aes(fill = ..count.. ))+
  viridis::scale_fill_viridis(trans = 'log10', option = 'A')+
  ggtitle('filtered')+
  facet_grid(broad~hpa1)

NA

fxn expressed

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad %>% 
  # filter(is.na(group)) %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  filter(!is.na(hpa)) %>% 
  ggplot(aes( fxn_exp, fill = hpa))+
  geom_density(aes(color = hpa), alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,.25), ylim = c(0,5))+
  theme(legend.position = 'top')

# seaad %>% group_by(cellType) %>% summarise(mn = median(fraction_expressed))

seaad %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.75)) %>% 
  ggplot(., aes(fxn_exp, broad, fill = hpa)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5)) +
  # geom_point(aes(x = top_fxn, color = hpa))+
  # stat_summary(fun = function(x) quantile(x,0.5), geom="point", size=2, color="red", position = 'dodge')+
  # ggforce::facet_zoom(xlim = c(0,0.08), horizontal = F)
  coord_cartesian(xlim = c(0,0.25))

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad %>% 
  # filter(is.na(group)) %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ paste0('HPA brain (n = ', length(intersect(gene, brain.genes)),' genes)'),
      gene %in% tad.deg ~ paste0('TAD DEG (n = ', length(intersect(gene,tad.deg)),' genes)'),
      gene %in% not.brain ~ paste0('HPA not brain (n = ', length(intersect(gene,not.brain)),' genes)'),
      T ~ paste0('other (n = ', length(unique(setdiff(gene, union(union(brain.genes, tad.deg), not.brain)))) ,' genes)')
      )
  ) %>% 
  filter(!is.na(hpa)) %>% 
  ggplot(aes( fxn_exp, fill = hpa))+
  # geom_density(aes(color = hpa), alpha = .1)+
  geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,.25), ylim = c(0,1e5))+
  theme(legend.position = 'top')

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  
  ggplot(aes( fxn_exp, fill = hpa1))+
  # geom_density(aes(color = hpa1), alpha = .1)+
  geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,.25), ylim = c(0,1e5))+
  theme(legend.position = 'top')

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  
  ggplot(aes( fxn_exp, color = hpa1))+
  geom_density( alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  geom_vline(xintercept = 0.2, lty = 2)+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,.25), ylim = c(0,1.7))+#
  theme(legend.position = 'top')

# seaad %>% group_by(cellType) %>% summarise(mn = median(fraction_expressed))

seaad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 

  ggplot(., aes(fxn_exp, broad, fill = hpa1)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5), trim = F) +
  # geom_point(aes(x = top_fxn, color = hpa))+
  # stat_summary(fun = function(x) quantile(x,0.5), geom="point", size=2, color="red", position = 'dodge')+
  # ggforce::facet_zoom(xlim = c(0,0.08), horizontal = F)
  coord_cartesian(xlim = c(0,1))

avg expression

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad %>% 
  # filter(is.na(group)) %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 
  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  ggplot(aes( (upperQ_exp), fill = hpa1))+
  geom_density(aes(color = hpa), alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,2), ylim = c(0,1.3) )+
  theme(legend.position = 'top')

# seaad %>% group_by(cellType) %>% summarise(mn = median(fraction_expressed))

seaad %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 
  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.75)) %>% 
  ggplot(., aes(upperQ_exp, broad, fill = hpa1)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5)) +
  # geom_point(aes(x = top_exp, color = hpa))+
  # stat_summary(fun = function(x) quantile(x,0.5), geom="point", size=2, color="red", position = 'dodge')+
  # ggforce::facet_zoom(xlim = c(0,0.08), horizontal = F)
  coord_cartesian(xlim = c(0,6))

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad %>% 
  # filter(is.na(group)) %>% 
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 
  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  ggplot(aes( (upperQ_exp), fill = hpa1))+
  # geom_density(aes(color = hpa), alpha = .1)+
  geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,2), ylim = c(0,3.5e4) )+
  theme(legend.position = 'top')

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 
  
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  
  ggplot(aes( upperQ_exp, fill = hpa1))+
  # geom_density(aes(color = hpa), alpha = .1)+
  geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(fill = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,2), ylim = c(0,3.5e4) )+
  theme(legend.position = 'top')

# also "brain genes":
# scores %>% filter(isScored_omics == 'Y', OmicsScore > 0) %>% pull(GeneName) %>% unique()

seaad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 

  ggplot(aes( upperQ_exp, color = hpa1 ))+
  geom_density( alpha = .1)+
  # geom_histogram(position = 'dodge')+
  # scale_y_log10()+
  scale_fill_discrete('')+scale_color_discrete('')+
  guides(color = guide_legend(nrow=2))+
  ggforce::facet_zoom(xlim = c(0,2), ylim = c(0,1.3) )+
  theme(legend.position = 'top')

# seaad %>% group_by(cellType) %>% summarise(mn = median(fraction_expressed))

seaad %>% 
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%
  mutate(
    hpa = case_when(
      gene %in% brain.genes ~ 'brain.genes',
      gene %in% tad.deg ~ 'tad.deg',
      gene %in% not.brain ~ 'not.brain',
      T ~ 'other')
  ) %>% 
  filter(!is.na(hpa)) %>% 

  # group_by(cellType, hpa) %>% 
  # mutate(top_exp = quantile(upperQ_exp, 0.75),
  #        top_fxn = quantile(fxn_exp, 0.95)) %>% 
  # group_by(cellType) %>%  
  # filter( upperQ_exp > unique(top_exp[hpa == 'not.brain']) ,
  #         fxn_exp > unique(top_fxn[hpa == 'not.brain']) ) %>% 
  # ungroup() %>% 

  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3) %>%
  
  # filter( upperQ_exp >= 2 | (upperQ_exp >= 1.33 & fxn_exp >= 0.2) ) %>%

  group_by(hpa) %>% 
  mutate(
    n = length(unique(gene)),
    hpa1 = paste0(hpa, ', ', n)
    ) %>% 
  
  ggplot(., aes(upperQ_exp, broad, fill = hpa1)) + 
  geom_violin(scale = 'width', draw_quantiles = c(.5), trim = F) +
  # geom_point(aes(x = top_exp, color = hpa))+
  # stat_summary(fun = function(x) quantile(x,0.5), geom="point", size=2, color="red", position = 'dodge')+
  # ggforce::facet_zoom(xlim = c(0,0.08), horizontal = F)
  coord_cartesian(xlim = c(0,6))

seaad.genes <- seaad %>% 
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3 ) %>%
  pull(gene) %>% 
  unique()

NODE: overall

tot.nodes = v.attr$name
filt.nodes = union(seaad.genes, tad.deg) %>% union(., brain.genes) %>% intersect(.,v.attr$name) 

grid::grid.newpage()
grid::grid.draw(
  VennDiagram::venn.diagram(
        x = list(
          `PathCommons_NW\n(19087)` = v.attr$name %>% .[!is.na(.)], 
          `HumanProtAtlas_brain\n(4140)` = brain.genes %>% .[!is.na(.)],
          `SeaAD\n(10594)` = seaad.genes %>% .[!is.na(.)],
          `TreatAD_DEG\n(11910)` = tad.deg %>% .[!is.na(.)]
        ),
        filename = NULL,
        force.unique = T,
        lty = 0, alpha = .3 , 
        fill = c('light blue','yellow', 'green','purple'),
        
        sub = paste0('# Pathway Commons nodes: ', length(tot.nodes),
                     '\n# filtered nodes: ', length(filt.nodes), 
                     ' (', signif( 100*length(filt.nodes)/length(tot.nodes), digits = 4), '%)' ),
        
        cat.cex = .8,
        ext.pos = 180,
        ext.dist = -.1
        )
)

EDGE: Pathway Commons Network

Specify the directed-edge types to filter the Pathway Commons graph

directed_edge_types = c("catalysis-precedes",
                        "controls-expression-of",
                        "controls-phosphorylation-of",
                        "controls-state-change-of",
                        "controls-transport-of"
                        )

# dir.net <- graph_from_data_frame(d = net.tbl %>% filter(interaction %in% directed_edge_types), directed = T)

How many edges from each source?

bind_cols(
    sources = str_split(net.tbl$sources,',') %>% unlist %>% unique, 
    n_edge = map_dbl( 
        str_split(net.tbl$sources,',') %>% unlist %>% unique, 
        ~ net.tbl %>% filter(grepl(.x, sources)) %>% nrow() ),
    any_directed = map_lgl(
        str_split(net.tbl$sources,',') %>% unlist %>% unique, 
        ~ net.tbl %>% 
            mutate(directed = if_else(interaction %in% directed_edge_types, 'dir','undir') ) %>% 
            filter(grepl(.x, sources)) %>% pull(directed) %>% any(. == 'dir')
    )
) %>% 
  mutate(any_directed = if_else(is.na(any_directed), FALSE, TRUE),
         any_directed = factor(any_directed, levels=c('TRUE','FALSE'))) %>%
  arrange(desc(n_edge)) %>% mutate(sources = fct_relevel(sources, sources)) %>%
  ggplot(aes(sources, n_edge)) + geom_bar(stat = 'identity', aes(fill = any_directed)) +
  # scale_y_log10()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)
        , legend.position = 'top')

Which edge sources are (generally) well supported?

bind_cols(
    sources = str_split(net.tbl$sources,',') %>% unlist %>% unique, 
    n_edge = map_dbl( 
      str_split(net.tbl$sources,',') %>% unlist %>% unique, 
      ~ net.tbl %>% filter(grepl(.x, sources)) %>% nrow() )
    , median_evidence_per_edge = map_dbl( 
      str_split(net.tbl$sources,',') %>% unlist %>% unique, 
      ~ net.tbl %>% filter(grepl(.x, sources)) %>% pull(n_edge_evidence) %>% median() )
    , any_directed = map_lgl(
        str_split(net.tbl$sources,',') %>% unlist %>% unique, 
        ~ net.tbl %>% 
            mutate(directed = if_else(interaction %in% directed_edge_types, 'dir','undir') ) %>% 
            filter(grepl(.x, sources)) %>% pull(directed) %>% any(. == 'dir') )
) %>% 
  mutate(any_directed = if_else(is.na(any_directed), FALSE, TRUE),
         any_directed = factor(any_directed, levels=c('TRUE','FALSE'))) %>%
  arrange(desc(n_edge)) %>% mutate(sources = fct_relevel(sources, sources)) %>% 
  ggplot(aes(n_edge, median_evidence_per_edge)) +
  geom_point( aes(color = any_directed )) + 
  scale_x_log10()+ 
  theme(legend.position = 'top')+
  ggrepel::geom_label_repel(aes(label = sources), size = 3)

  # theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) 

Distribution of evidence support for edges

net.tbl %>% 
  mutate(directed = if_else(interaction %in% directed_edge_types, 'dir','undir') ) %>% 
  ggplot(aes(n_edge_evidence))+
  stat_ecdf(geom = 'line', aes(color = directed))+
  # geom_density(aes(fill = directed))+
  # geom_histogram(aes(fill = directed), position = position_dodge())+
  # scale_y_log10()+
  scale_x_log10()+
  geom_vline(xintercept = 2, lty = 2, lwd = .5)+
  labs(y = 'fraction of edges')

Distribution of evidence support for edges

net.tbl %>% 
  mutate(directed = if_else(interaction %in% directed_edge_types, 'dir','undir') ) %>% 
  ggplot(aes(n_edge_types))+
  stat_ecdf(geom = 'line', aes(color = directed))+
  # geom_density(aes(fill = directed))+
  # geom_histogram(aes(fill = directed), position = position_dodge())+
  # scale_y_log10()+
  # scale_x_log10()+
  geom_vline(xintercept = 2, lty = 2, lwd = .5)+
  labs(y = 'fraction of edges')

Distribution of evidence support for edges

net.tbl %>% 
  mutate(directed = if_else(interaction %in% directed_edge_types, 'dir','undir') ) %>% 
  ggplot(aes(n_source))+
  stat_ecdf(geom = 'line', aes(color = directed))+
  # geom_density(aes(fill = directed))+
  # geom_histogram(aes(fill = directed), position = position_dodge())+
  # scale_y_log10()+
  scale_x_log10()+
  geom_vline(xintercept = 2, lty = 2, lwd = .5)+
  labs(y = 'fraction of edges')

Distribution of evidence support for edges

net.tbl %>% 
  mutate(directed = if_else(interaction %in% directed_edge_types, 'dir','undir') ) %>%
  filter(n_edge_evidence > 1
         | (n_edge_evidence == 1 & n_edge_types > 2 & n_source > 2)) %>% 
  ggplot(aes(n_edge))+
  # stat_ecdf(geom = 'line', aes(color = directed))+
  geom_histogram(color = 'grey20', fill = 'grey80')+
  
  # scale_x_log10()+
  # geom_vline(xintercept = 2, lty = 2, lwd = .5)+
  labs()

Distribution of evidence support for edges

net.tbl %>% 
  # mutate(directed = if_else(interaction %in% directed_edge_types, 'dir','undir') ) %>% 
  ggplot(aes( n_edge_types, n_edge_evidence ))+
  geom_point()+
  geom_smooth(method = 'lm')+
  scale_y_log10()+
  # scale_x_log10()+
  # geom_vline(xintercept = 2, lty = 2, lwd = .5)+
  labs()

EDGE: Pairwise partial correlations

Dropping this for the moment because: 1. the current pcor calculations would need to be recalculated on a tissue specific basis 2. the data are large, unwieldy, and of uncertain utility

May return at a later time.

EDGE: overall

Summary


# specify gene lists
hpa.brain <- tissue.array %>% 
  filter(
    Tissue %in% brain.tissues, 
    Level %in% c('Low','Medium','High','Ascending','Descending'),
    Reliability %in% c('Enhanced','Supported','Approved') ) %>% 
  pull(Gene.name) %>% unique()

tad.deg <- scores %>% 
  filter(isScored_omics == 'Y', OmicsScore > 0) %>% 
  pull(GeneName) %>% unique()

seaad.expr <- seaad %>% 
  filter( upperQ_exp >= -2.5 * fxn_exp + 2.3 ) %>%
  pull(gene) %>% unique()

brain.genes <- union(hpa.brain, tad.deg) %>% union(., seaad.expr)

# pull NW stats based on filter
nw.stats <- tibble(  
  
  dir = c(
    'undirected'
    ,'directed'
    
    ,'undirected'
    ,'directed'
    
    ,'undirected'
    ,'directed'
    
    ,'undirected'
    ,'directed'
    
    ,'undirected'
    ,'directed'
    
    ,'undirected'
    ,'directed'
    
    ,'undirected'
    ,'directed'
    
    ), 
  
  filt = c(
    'none'
    ,'none'
    
    ,'edge_evidence > 1'
    ,'edge_evidence > 1'
    
    ,'HPA_brain'
    ,'HPA_brain'
    
    ,'omics_detect'
    ,'omics_detect'
    
    ,'seaAD_detect'
    ,'seaAD_detect'
    
    ,'all_expr'
    ,'all_expr'

    ,'expr+evidence'
    ,'expr+evidence'

        
    ),
  
  nV = c( 
    net.tbl %>% 
      graph_from_data_frame %>% V %>% length
    , net.tbl %>% 
      filter(interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% V %>% length

    , net.tbl %>% 
      filter(n_edge_evidence > 1) %>% 
      graph_from_data_frame %>% V %>% length
    , net.tbl %>% 
      filter(n_edge_evidence > 1, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% V %>% length

    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain) %>% 
      graph_from_data_frame %>% V %>% length
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% V %>% length
    
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg) %>% 
      graph_from_data_frame %>% V %>% length
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% V %>% length
    
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr) %>% 
      graph_from_data_frame %>% V %>% length
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% V %>% length
    
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% V %>% length
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% V %>% length
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% V %>% length
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% V %>% length
    
    ),
  
  nE = c( 
    net.tbl %>% 
      graph_from_data_frame %>% E %>% length
    , net.tbl %>% 
      filter(interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% E %>% length
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1) %>% 
      graph_from_data_frame %>% E %>% length
    , net.tbl %>% 
      filter(n_edge_evidence > 1, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% E %>% length
    
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain) %>% 
      graph_from_data_frame %>% E %>% length
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% E %>% length
    
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg) %>% 
      graph_from_data_frame %>% E %>% length
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% E %>% length
    
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr) %>% 
      graph_from_data_frame %>% E %>% length
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% E %>% length
    
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% E %>% length
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% E %>% length
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% E %>% length
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% E %>% length
    
    ),
  
  avg_path_length = c(
    net.tbl %>% 
      graph_from_data_frame %>% average.path.length()
    , net.tbl %>% 
      filter(interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% average.path.length(directed = T)
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1) %>% 
      graph_from_data_frame %>% average.path.length()
    , net.tbl %>% 
      filter(n_edge_evidence > 1, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% average.path.length(directed = T)
    
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain) %>% 
      graph_from_data_frame %>% average.path.length()
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% average.path.length(directed = T)
    
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg) %>% 
      graph_from_data_frame %>% average.path.length()
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% average.path.length(directed = T)
    
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr) %>% 
      graph_from_data_frame %>% average.path.length()
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% average.path.length(directed = T)

    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% average.path.length()
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% average.path.length(directed = T)
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% average.path.length()
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% average.path.length(directed = T)    
  ),
  
  assortativity_coef = c(
    net.tbl %>% 
      graph_from_data_frame %>% assortativity(., types1 = V(.))
    , net.tbl %>% 
      filter(interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% assortativity(., types1 = V(.))
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1) %>% 
      graph_from_data_frame %>% assortativity(., types1 = V(.))
    , net.tbl %>% 
      filter(n_edge_evidence > 1, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% assortativity(., types1 = V(.))
    
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain) %>% 
      graph_from_data_frame %>% assortativity(., types1 = V(.))
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% assortativity(., types1 = V(.))
    
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg) %>% 
      graph_from_data_frame %>% assortativity(., types1 = V(.))
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% assortativity(., types1 = V(.))
    
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr) %>% 
      graph_from_data_frame(directed=T) %>% assortativity(., types1 = V(.))
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% assortativity(., types1 = V(.))
    
    
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% assortativity(., types1 = V(.))
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame %>% assortativity(., types1 = V(.))
    
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% assortativity(., types1 = V(.))
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame %>% assortativity(., types1 = V(.))
  ),
  
  connected_components = c(
    net.tbl %>% 
      graph_from_data_frame %>% no.clusters()
    , net.tbl %>% 
      filter(interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% no.clusters()
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1) %>% 
      graph_from_data_frame %>% no.clusters()
    , net.tbl %>% 
      filter(n_edge_evidence > 1, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% no.clusters()
    
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain) %>% 
      graph_from_data_frame %>% no.clusters()
    , net.tbl %>% 
      filter(from %in% hpa.brain & to %in% hpa.brain, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% no.clusters()
    
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg) %>% 
      graph_from_data_frame %>% no.clusters()
    , net.tbl %>% 
      filter(from %in% tad.deg & to %in% tad.deg, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% no.clusters()
    
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr) %>% 
      graph_from_data_frame %>% no.clusters()
    , net.tbl %>% 
      filter(from %in% seaad.expr & to %in% seaad.expr, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% no.clusters()
    
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% no.clusters()
    , net.tbl %>% 
      filter(from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% no.clusters()
    
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes) %>% 
      graph_from_data_frame %>% no.clusters()
    , net.tbl %>% 
      filter(n_edge_evidence > 1,
             from %in% brain.genes & to %in% brain.genes, 
             interaction %in% directed_edge_types) %>% 
      graph_from_data_frame(directed=T) %>% no.clusters()
  )
  
)
nw.stats %>% 
  pivot_longer(cols = c(nV,nE,avg_path_length,assortativity_coef,connected_components), 
               names_to = 'prop', values_to = 'val') %>% 
  mutate(prop = factor(prop, levels = c('nV','nE', 'avg_path_length','assortativity_coef','connected_components'))
         , dir = factor(dir, levels = c('undirected','directed'))
         , filt = factor(filt, levels = c('none','edge_evidence > 1','HPA_brain','omics_detect','seaAD_detect', 
                                          'all_expr','expr+evidence'))
         ) %>% 
  ggplot(aes(filt, val, fill = dir)) +
  geom_bar(stat = 'identity', position = 'dodge')+
  theme(legend.position = 'top',
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1))+
  facet_wrap(~prop, scales = 'free_y', ncol = 2)

Session

save.image(
  paste0(
    Sys.Date() %>% str_replace_all('-','_'),
    '_',
    'base_nw_filtering.Rdata')
  )
sessionInfo()
R version 4.2.1 (2022-06-23)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.5 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/liblapack.so.3

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8   
 [6] LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices datasets  utils     methods   base     

other attached packages:
 [1] forcats_0.5.1   stringr_1.4.0   dplyr_1.0.4     purrr_0.3.4     readr_1.4.0     tidyr_1.1.2     tibble_3.0.6    ggplot2_3.3.3   tidyverse_1.3.0
[10] tidygraph_1.2.0 igraph_1.2.6    synapser_0.11.7

loaded via a namespace (and not attached):
 [1] nlme_3.1-157           fs_1.5.0               lubridate_1.7.9.2      httr_1.4.2             rprojroot_2.0.2        tools_4.2.1           
 [7] backports_1.2.1        utf8_1.1.4             R6_2.5.0               DT_0.17                mgcv_1.8-34            DBI_1.1.1             
[13] lazyeval_0.2.2         colorspace_2.0-0       withr_2.4.1            tidyselect_1.1.0       gridExtra_2.3          curl_4.3              
[19] compiler_4.2.1         VennDiagram_1.6.20     cli_2.3.0              rvest_0.3.6            formatR_1.7            xml2_1.3.2            
[25] plotly_4.9.3           labeling_0.4.2         scales_1.1.1           digest_0.6.27          rmarkdown_2.20         pkgconfig_2.0.3       
[31] htmltools_0.5.4        parallelly_1.23.0      dbplyr_2.1.0           fastmap_1.1.0          htmlwidgets_1.5.3      rlang_0.4.10          
[37] readxl_1.3.1           rstudioapi_0.13        farver_2.0.3           generics_0.1.0         jsonlite_1.7.2         crosstalk_1.1.1       
[43] magrittr_2.0.1         Matrix_1.4-1           futile.logger_1.4.3    fansi_0.4.2            Rcpp_1.0.6             munsell_0.5.0         
[49] viridis_0.5.1          lifecycle_1.0.0        furrr_0.2.2            stringi_1.5.3          yaml_2.2.1             MASS_7.3-57           
[55] grid_4.2.1             parallel_4.2.1         listenv_0.8.0          ggrepel_0.9.1          crayon_1.4.1           lattice_0.20-45       
[61] splines_4.2.1          haven_2.3.1            cowplot_1.1.1          hms_1.0.0              knitr_1.31             pillar_1.4.7          
[67] codetools_0.2-18       PythonEmbedInR_0.12.79 futile.options_1.0.1   reprex_1.0.0           glue_1.4.2             gprofiler2_0.2.0      
[73] evaluate_0.14          lambda.r_1.2.4         data.table_1.13.6      renv_0.16.0-65         BiocManager_1.30.10    modelr_0.1.8          
[79] vctrs_0.3.6            tweenr_1.0.1           cellranger_1.1.0       gtable_0.3.0           polyclip_1.10-0        future_1.21.0         
[85] assertthat_0.2.1       pack_0.1-1             xfun_0.37              ggforce_0.3.2          broom_0.7.4            viridisLite_0.3.0     
[91] globals_0.14.0         ellipsis_0.3.1         here_1.0.1            
LS0tCnRpdGxlOiAiTmV0d29yayBGaWx0ZXJpbmcgQW5hbHlzaXMiCmF1dGhvcjogIkdyZWcgQ2FyeSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgZmlnX3dpZHRoOiA1CiAgICBmaWdfaGVpZ2h0OiA0CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICBjc3M6IHN0eWxlLmNzcwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgoKYGBge3Igc2V0dXB9CmxpYnJhcnkoc3luYXBzZXIpCiMgbGlicmFyeShwYXh0b29sc3IpCiMgbGlicmFyeShvcmcuSHMuZWcuZGIpCiMgbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCiMgbGlicmFyeShIb3ROZXR2aWV3ZVIpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KHRpZHlncmFwaCkKbGlicmFyeSh0aWR5dmVyc2UpCgojIHNvdXJjZShwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvLi4vYmlvZG9tX3RhbGx5LlInKSkKIyBzb3VyY2UocGFzdGUwKGhlcmU6OmhlcmUoKSwnLy4uL2Jpb2RvbV9lbnIuUicpKQojIHNvdXJjZShwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvLi4vYmlvZG9tX2Vucl9wbG90cy5SJykpCgp0aGVtZV9zZXQodGhlbWVfYncoKSkKYGBgCgojIEdhdGhlciBkYXRhCkdyYWIgcmVsZXZhbnQgZGF0YSBmcm9tIHN5bmFwc2UsIGluY2x1ZGluZzogIAoxKSBUYXJnZXQgUmlzayBTY29yZXMgKFtzeW4yNTU3NTE1Nl0oaHR0cHM6Ly93d3cuc3luYXBzZS5vcmcvIyFTeW5hcHNlOnN5bjI1NTc1MTU2KXt0YXJnZXQ9Il9ibGFuayJ9KSBhbmQgT21pY3MgU2NvcmVzIChbc3luMjI3NTg1MzZdKGh0dHBzOi8vd3d3LnN5bmFwc2Uub3JnLyMhU3luYXBzZTpzeW4yMjc1ODUzNil7dGFyZ2V0PSJfYmxhbmsifSkgIAoyKSBCaW9kb21haW4gRGVmaW5pdGlvbnMgKFtzeW4yNTQyODk5Ml0oaHR0cHM6Ly93d3cuc3luYXBzZS5vcmcvIyFTeW5hcHNlOnN5bjI1NDI4OTkyKXt0YXJnZXQ9Il9ibGFuayJ9KSAgCjMpIFBhdGh3YXkgQ29tbW9ucyBGdWxsIEdyYXBoLCB2MTIgKFtzeW41MTA4MDkzMl0oaHR0cHM6Ly93d3cuc3luYXBzZS5vcmcvIyFTeW5hcHNlOnN5bjUxMDgwOTMyKXt0YXJnZXQ9Il9ibGFuayJ9KSAgCjQpIEh1bWFuIFByb3RlaW4gQXRsYXMgdGlzc3VlIGltbXVub2hpc3RvY2hlbWlzdHJ5IG1pY3JvIGFycmF5IGRhdGEgKFtzeW41MTA3NDU5OF0oaHR0cHM6Ly93d3cuc3luYXBzZS5vcmcvIyFTeW5hcHNlOnN5bjUxMDc0NTk4KXt0YXJnZXQ9Il9ibGFuayJ9KSAgCjUpIFJOQSBCcmFpbiBHVEV4IChbc3luNTEwNzQ2MzldKGh0dHBzOi8vd3d3LnN5bmFwc2Uub3JnLyMhU3luYXBzZTpzeW41MTA3NDYzOSl7dGFyZ2V0PSJfYmxhbmsifSkgIAo2KSBBTVAtQUQgY29ob3J0IHBhaXJ3aXNlIHBhcnRpYWwgY29ycmVsYXRpb25zIChbUk9TTUFQXShodHRwczovL3d3dy5zeW5hcHNlLm9yZy8jIVN5bmFwc2U6c3luNTEwNjE3OTApe3RhcmdldD0iX2JsYW5rIn0sIFtNYXlvXShodHRwczovL3d3dy5zeW5hcHNlLm9yZy8jIVN5bmFwc2U6c3luNTEwNjE2MTQpe3RhcmdldD0iX2JsYW5rIn0sIFtNU0JCXShodHRwczovL3d3dy5zeW5hcHNlLm9yZy8jIVN5bmFwc2U6c3luNTEwNjEzMjQpe3RhcmdldD0iX2JsYW5rIn0pOyB0aGVzZSBhcmUgcXVpdGUgbGFyZ2UhICg+IDYgR0IpLCB3YWl0IHRvIGxvYWQgdW50aWwgcGVyZm9ybWluZyB0aGlzIGFuYWx5c2lzICAKNykgU0VBLUFEIHNpbmdsZSBjZWxsIGRhdGEgKFtzeW41MTQ0MTEwNV0oaHR0cHM6Ly93d3cuc3luYXBzZS5vcmcvIyFTeW5hcHNlOnN5bjUxNDQxMTA1KXt0YXJnZXQ9Il9ibGFuayJ9KSAgCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnN5bkxvZ2luKCkKCiMgdGFyZ2V0IHJpc2sgc2NvcmVzCnNjb3JlcyA8LSByZWFkX2NzdihzeW5UYWJsZVF1ZXJ5KCdzZWxlY3QgKiBmcm9tIHN5bjI1NTc1MTU2JywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVSb3dJZEFuZFJvd1ZlcnNpb24gPSBGKSRmaWxlcGF0aCkKb21pY3MgPC0gcmVhZF9jc3Yoc3luVGFibGVRdWVyeSgnc2VsZWN0ICogZnJvbSBzeW4yMjc1ODUzNicsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVSb3dJZEFuZFJvd1ZlcnNpb24gPSBGKSRmaWxlcGF0aCkKCiMgYmlvbG9naWNhbCBkb21haW4gYW5ub3RhdGlvbnMKYmlvZG9tIDwtIGZ1bGxfam9pbigKICAjIGJpb2RvbWFpbnMKICByZWFkUkRTKHN5bkdldCgnc3luMjU0Mjg5OTInKSRwYXRoKSwKICAjIGRvbWFpbiBsYWJlbHMKICByZWFkX2NzdihzeW5HZXQoJ3N5bjI2ODU2ODI4JykkcGF0aCksCiAgYnkgPSBjKCdCaW9kb21haW4nPSdkb21haW4nKQopICU+JQogIG11dGF0ZShCaW9kb21haW4gPSBjYXNlX3doZW4oQmlvZG9tYWluID09ICdub25lJyB+IE5BX2NoYXJhY3Rlcl8sIFQgfiBCaW9kb21haW4pKQoKIyBwYXRod2F5IGNvbW1vbnMgZ3JhcGgKbmV0IDwtIGlncmFwaDo6cmVhZF9ncmFwaChzeW5HZXQoJ3N5bjUxMDgwOTMyJykkcGF0aCwgZm9ybWF0ID0gJ2dyYXBobWwnKSAKCiMgSHVtYW4gcHJvdGVpbiBhdGxhcyBpbmZvCnRpc3N1ZS5hcnJheSA8LSByZWFkX2NzdihzeW5HZXQoJ3N5bjUxMDc0NTk4JykkcGF0aCkKYnJhaW4uZ3RleCA8LSByZWFkX2NzdihzeW5HZXQoJ3N5bjUxMDc0NjM5JykkcGF0aCkKCiMgc2luZ2xlIGNlbGwKc2VhYWQgPC0gcmVhZF9jc3Yoc3luR2V0KCdzeW41MTE5NzgwMycpJHBhdGgsIGd1ZXNzX21heCA9IDJlNSkKc2VhYWQuYnJvYWQgPC0gcmVhZF9jc3Yoc3luR2V0KCdzeW41MTQ0MTEwNScpJHBhdGgsIGd1ZXNzX21heCA9IDJlNSkKYGBgCgoKRXh0cmFjdCB0aGUgY29yZSBOVyB0YWJsZXMKYGBge3IgbWVzc2FnZT1GQUxTRX0KbmV0LnRibCA8LSBpZ3JhcGg6OmFzX2RhdGFfZnJhbWUobmV0KQoKdi5hdHRyIDwtIHRpYmJsZSggbmEgPSB2ZXJ0ZXguYXR0cmlidXRlcyhuZXQpICkgJT4lCiAgdCgpICU+JSBhc190aWJibGUocm93bmFtZXMgPSBOQSwgLm5hbWVfcmVwYWlyID0gJ3VuaXF1ZScpICU+JSB1bm5lc3QoZXZlcnl0aGluZygpKSAlPiUKICByZW5hbWVfd2l0aCguLCB+bmFtZXModmVydGV4LmF0dHJpYnV0ZXMobmV0KSksIGV2ZXJ5dGhpbmcoKSkKCmUuYXR0ciA8LSB0aWJibGUoIGVhID0gZWRnZS5hdHRyaWJ1dGVzKG5ldCkgKSAlPiUgCiAgdCgpICU+JSBhc190aWJibGUocm93bmFtZXMgPSBOQSwgLm5hbWVfcmVwYWlyID0gJ3VuaXF1ZScpICU+JSB1bm5lc3QoZXZlcnl0aGluZygpKSAlPiUgCiAgcmVuYW1lX3dpdGgoLiwgfm5hbWVzKGVkZ2UuYXR0cmlidXRlcyhuZXQpKSwgZXZlcnl0aGluZygpKQpgYGAKCiMgTk9ERTogSHVtYW4gUHJvdGVpbiBBdGxhcyAKClNwZWNpZnkgYnJhaW4gdGlzc3VlIHR5cGVzCmBgYHtyfQpicmFpbi50aXNzdWVzIDwtIGMoCiAiY2F1ZGF0ZSIsICJjZXJlYmVsbHVtIiwgImNlcmVicmFsIGNvcnRleCIsICJoaXBwb2NhbXB1cyIsIAogImh5cG90aGFsYW11cyIsICJwaXR1aXRhcnkgZ2xhbmQiLCAiZG9yc2FsIHJhcGhlIiwgCiAiY2hvcm9pZCBwbGV4dXMiLCAic3Vic3RhbnRpYSBuaWdyYSIKKQoKYnJhaW4uZ2VuZXMgPC0gdGlzc3VlLmFycmF5ICU+JSBmaWx0ZXIoCiAgVGlzc3VlICVpbiUgYnJhaW4udGlzc3VlcywgCiAgTGV2ZWwgJWluJSBjKCdMb3cnLCdNZWRpdW0nLCdIaWdoJywnQXNjZW5kaW5nJywnRGVzY2VuZGluZycpLAogIFJlbGlhYmlsaXR5ICVpbiUgYygnRW5oYW5jZWQnLCdTdXBwb3J0ZWQnLCdBcHByb3ZlZCcpCikgJT4lIHB1bGwoR2VuZS5uYW1lKSAlPiUgdW5pcXVlKCkKCm5vdC5icmFpbiA8LSB0aXNzdWUuYXJyYXkgJT4lIGZpbHRlcigKICBUaXNzdWUgJWluJSBicmFpbi50aXNzdWVzLAogIExldmVsICVpbiUgYygnTm90IGRldGVjdGVkJyksCiAgUmVsaWFiaWxpdHkgJWluJSBjKCdFbmhhbmNlZCcsJ1N1cHBvcnRlZCcsJ0FwcHJvdmVkJykKKSAlPiUgcHVsbChHZW5lLm5hbWUpICU+JSB1bmlxdWUoKQoKYGBgCgoKYGBge3J9CiMgYWxzbyAiYnJhaW4gZ2VuZXMiOgojIHNjb3JlcyAlPiUgZmlsdGVyKGlzU2NvcmVkX29taWNzID09ICdZJywgT21pY3NTY29yZSA+IDApICU+JSBwdWxsKEdlbmVOYW1lKSAlPiUgdW5pcXVlKCkKCmJyYWluLmd0ZXggJT4lIAogIG11dGF0ZShocGEgPSBjYXNlX3doZW4oR2VuZS5uYW1lICVpbiUgYnJhaW4uZ2VuZXMgfiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCdicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoR2VuZS5uYW1lLCBicmFpbi5nZW5lcykpLCcgZ2VuZXMpJyksCiAgICAgICAgICAgICAgICAgICAgICAgICBHZW5lLm5hbWUgJWluJSBub3QuYnJhaW4gfiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCdub3QgYnJhaW4gKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KEdlbmUubmFtZSxub3QuYnJhaW4pKSwnIGdlbmVzKScpLAogICAgICAgICAgICAgICAgICAgICAgICAgVCB+IE5BX2NoYXJhY3Rlcl8pKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCiAgZ2dwbG90KGFlcyggbG9nMTAoblRQTSksIGZpbGwgPSBocGEpKSsKICBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhKSwgYWxwaGEgPSAuMSkrCiAgIyBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoJycpK3NjYWxlX2NvbG9yX2Rpc2NyZXRlKCcnKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykKYGBgCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CnRhZC5kZWcgPC0gc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKYnJhaW4uZ3RleCAlPiUgCiAgbXV0YXRlKGhwYSA9IGNhc2Vfd2hlbihHZW5lLm5hbWUgJWluJSB0YWQuZGVnIH4gcGFzdGUwKCdUQUQgREVHIChuID0gJywgbGVuZ3RoKGludGVyc2VjdChHZW5lLm5hbWUsdGFkLmRlZykpLCcgZ2VuZXMpJyksCiAgICAgICAgICAgICAgICAgICAgICAgICBUIH4gcGFzdGUwKCdub3QgVEFEIERFRyAobiA9ICcsIGxlbmd0aChzZXRkaWZmKEdlbmUubmFtZSwgdGFkLmRlZykpLCcgZ2VuZXMpJyksCiAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCiAgZ2dwbG90KGFlcyggbG9nMTAoblRQTSksIGZpbGwgPSBocGEpKSsKICBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhKSwgYWxwaGEgPSAuMSkrCiAgIyBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoJycpK3NjYWxlX2NvbG9yX2Rpc2NyZXRlKCcnKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykKYGBgCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CnRhZC5kZWcgPC0gc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKYnJhaW4uZ3RleCAlPiUgCiAgbXV0YXRlKAogIGhwYSA9IGNhc2Vfd2hlbigKICAgIEdlbmUubmFtZSAlaW4lIGJyYWluLmdlbmVzIH4gCiAgICAgIHBhc3RlMCgnSFBBIGJyYWluIChuID0gJywgbGVuZ3RoKGludGVyc2VjdChHZW5lLm5hbWUsIGJyYWluLmdlbmVzKSksJyBnZW5lcyknKSwKICAgIEdlbmUubmFtZSAlaW4lIHRhZC5kZWcgfiBwYXN0ZTAoJ1RBRCBERUcgKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KEdlbmUubmFtZSx0YWQuZGVnKSksJyBnZW5lcyknKSwKICAgIEdlbmUubmFtZSAlaW4lIG5vdC5icmFpbiB+IHBhc3RlMCgnSFBBIG5vdCBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoR2VuZS5uYW1lLG5vdC5icmFpbikpLCcgZ2VuZXMpJyksCiAgICBUIH4gcGFzdGUwKCdvdGhlciAobiA9ICcsIGxlbmd0aChzZXRkaWZmKEdlbmUubmFtZSwgdW5pb24odW5pb24oYnJhaW4uZ2VuZXMsIHRhZC5kZWcpLCBub3QuYnJhaW4pKSkgLCcgZ2VuZXMpJykKICAgICkpICU+JSAKICBnZ3Bsb3QoYWVzKCBsb2cxMChuVFBNKSwgZmlsbCA9IGhwYSkpKwogIGdlb21fZGVuc2l0eShhZXMoY29sb3IgPSBocGEpLCBhbHBoYSA9IC4xKSsKICAjIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gJ2RvZGdlJykrCiAgIyBzY2FsZV95X2xvZzEwKCkrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgnJykrc2NhbGVfY29sb3JfZGlzY3JldGUoJycpKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKG5yb3c9MikpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnKQpgYGAKCiMgTk9ERTogU0VBLUFEIHNpbmdsZSBjZWxsIGRhdGEKCiMjIHN1YmNsYXNzCiMjIyBib3RoIGRpbWVuc2lvbnMKCmBgYHtyfQp0ID0gLjkKCnRtcCA9IHNlYWFkLmJyb2FkICU+JSAKCiAgIyBmaWx0ZXIoZ2VuZSAlaW4lIG5vdC5icmFpbikgJT4lIAogICMgbXV0YXRlKGhwYSA9ICdub3QnKSAlPiUgCgogIG11dGF0ZSgKICAgICAgaHBhID0gY2FzZV93aGVuKAogICAgICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluJywKICAgICAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90JywKICAgICAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gJ2RlZycsCiAgICAgICAgICBUIH4gJ290aGVyJwogICAgICApCiAgKSAlPiUKCiAgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogIHN1bW1hcmlzZSggCiAgICBleHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCB0KSwgCiAgICBmeG4gPSBxdWFudGlsZShmeG5fZXhwLCB0KQogICAgKSAKCiMgYmluZF9yb3dzKAojICAgICB0bXAsIAojICAgICB0bXAgJT4lIGZpbHRlcihocGEgPT0gJ25vdCcpICU+JSBtdXRhdGUoZXhwID0gZXhwICsgLjE0MiwgZnhuID0gZnhuICsgLjE0MiwgaHBhID0gJ25ldycpCiMgICApICU+JSAKdG1wICU+JSAKICBnZ3Bsb3QoYWVzKGZ4biwgZXhwLCBncm91cCA9IGhwYSkpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScsIGNvbG9yID0gJ2dyZXkyMCcsIGx3ZCA9IC41LCBsdHkgPSAyKSsKICAjIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDEuNTI5NCwgc2xvcGUgPSAtMi41NjI1NjkpKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDIuMywgc2xvcGUgPSAtMi41KSsKICBhbm5vdGF0ZShnZW9tID0gJ3RleHQnLCB4ID0gLjY1LCB5ID0gMCwgbGFiZWwgPSAneSA9IC0yLjV4ICsgMi4zJywgaGp1c3QgPSAwKSsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNlbGxUeXBlLCBzaGFwZSA9IGhwYSksIHNpemUgPSAyLCBhbHBoYSA9IC41KSsKICBsYWJzKHkgPSAncXVhbnRpbGUgZXhwcmVzc2lvbicsIHggPSAncXVhbnRpbGUgZnJhY3Rpb24gZXhwcmVzc2luZycsCiAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgncGxvdHRpbmcgcXVhbnRpbGU6ICcsIHQpKQoKYGBgCgoKYGBge3J9CnQgPSAuOQoKc2VhYWQuYnJvYWQgJT4lIAogIAogICMgZmlsdGVyKGdlbmUgJWluJSBub3QuYnJhaW4pICU+JSAKICAjIG11dGF0ZShocGEgPSAnbm90JykgJT4lIAoKICBtdXRhdGUoCiAgICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgICAgIGdlbmUgJWluJSBicmFpbi5nZW5lcyB+ICdicmFpbicsCiAgICAgICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gJ25vdCcsCiAgICAgICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICdkZWcnLAogICAgICAgICAgVCB+ICdvdGhlcicKICAgICAgKQogICkgJT4lCiAgZmlsdGVyKGhwYSA9PSAnbm90JykgJT4lCgogIGdyb3VwX2J5KGNlbGxUeXBlLCBocGEpICU+JQogIHN1bW1hcmlzZSggZXhwID0gcXVhbnRpbGUodXBwZXJRX2V4cCwgdCksIAogICAgICAgICAgICAgZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgdCkKICAgICAgICAgICAgICkgJT4lIAogIGxtKGV4cH5meG4sIGRhdGEgPSAuKSAlPiUgCiAgYnJvb206OnRpZHkoKQpgYGAKCmBgYHtyfQp4ID0gbWFwX2RmcigKICAgIHNlcSgxLjUsMy41LC4wMSksCiAgICB+ewogICAgICAgIHNlYWFkLmJyb2FkICU+JSAKICAgICAgICAgICAgZmlsdGVyKCB1cHBlclFfZXhwID49IC0yLjUgKiBmeG5fZXhwICsgLngpICU+JSAKICAgICAgICAgICAgc3VtbWFyaXNlKAogICAgICAgICAgICAgICAgaW50ID0gLngsCiAgICAgICAgICAgICAgICBuLmJyYWluID0gbGVuZ3RoKGludGVyc2VjdChnZW5lLCBicmFpbi5nZW5lcyApKSwKICAgICAgICAgICAgICAgIG4ubm90ID0gbGVuZ3RoKGludGVyc2VjdChnZW5lLG5vdC5icmFpbikpLAogICAgICAgICAgICAgICAgbi5kZWcgPSBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsdGFkLmRlZykpLAogICAgICAgICAgICAgICAgbi5vdGhlciA9IGxlbmd0aCh1bmlxdWUoc2V0ZGlmZihnZW5lLCB1bmlvbih1bmlvbihicmFpbi5nZW5lcywgdGFkLmRlZyksIG5vdC5icmFpbikpKSksCiAgICAgICAgICAgICAgICBkaWZmLmIgPSAobi5icmFpbiAtIG4ubm90KSwKICAgICAgICAgICAgICAgIHBjdC5iID0gMTAwKihkaWZmLmIvbi5icmFpbiksCiAgICAgICAgICAgICAgICBkaWZmLmQgPSBuLmRlZyAtIG4ubm90LAogICAgICAgICAgICAgICAgcGN0LmQgPSAxMDAqKGRpZmYuZC9uLmJyYWluKQogICAgICAgICAgICApCiAgICB9CikgJT4lIAogIGFycmFuZ2UoZGVzYyhkaWZmLmIpLCBkZXNjKHBjdC5kKSk7CgpxcGxvdCh4JGludCwgeCRkaWZmLmIsIGdlb20gPSAnbGluZScpCgpEVDo6ZGF0YXRhYmxlKHgpCmBgYAoKYGBge3J9CnQgPSAuOQoKdGhyZXNoID0gc2VhYWQuYnJvYWQgJT4lIAogIGZpbHRlcihnZW5lICVpbiUgbm90LmJyYWluKSAlPiUKICBncm91cF9ieShicm9hZCwgY2VsbFR5cGUpICU+JQogIHN1bW1hcmlzZSggCiAgICBleHAxID0gcXVhbnRpbGUodXBwZXJRX2V4cCwgdCksCiAgICBmeG4xID0gcXVhbnRpbGUoZnhuX2V4cCwgdCkKICApICU+JSAKICBtdXRhdGUoCiAgICBleHAgPSBleHAxKy4xNDIsCiAgICBmeG4gPSBmeG4xKy4xNDIsCiAgICBocGEgPSAnbmV3LmRhdCcKICApIAoKc2VhYWQuYnJvYWQgJT4lIAoKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluJywKICAgICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gJ25vdCcsCiAgICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAnZGVnJywKICAgICAgICBUIH4gJ290aGVyJykKICAgICAgKSAlPiUgCiAgZ2dwbG90KGFlcyhmeG5fZXhwLCB1cHBlclFfZXhwLCBncm91cCA9IGhwYSkpKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDIuMywgc2xvcGUgPSAtMi41KSsKICAjIGFubm90YXRlKGdlb20gPSAndGV4dCcsIHggPSAuNjUsIHkgPSAwLCBsYWJlbCA9ICd5ID0gLTIuNXggKyAyLjUnLCBoanVzdCA9IDApKwogIGdlb21fcG9pbnQoZGF0YSA9IHRocmVzaCwgYWVzKHggPSBmeG4sIHkgPSBleHApLCBzaXplID0gMiwgYWxwaGEgPSAuNSkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgYWVzKGNvbG9yID0gaHBhKSwgbHdkID0gLjUsIGx0eSA9IDIpKwogIGxhYnMoeSA9ICdleHByZXNzaW9uJywgeCA9ICdmcmFjdGlvbiBleHByZXNzaW5nJwogICAgICAgIywgc3VidGl0bGUgPSBwYXN0ZTAoJ3Bsb3R0aW5nIHF1YW50aWxlOiAnLCB0KQogICAgICAgKSsKICBmYWNldF93cmFwKH5icm9hZCwgc2NhbGVzID0gJ2ZyZWUnKQoKYGBgCmBgYHtyfQp0ID0gLjkKCnRocmVzaCA9IHNlYWFkLmJyb2FkICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIG5vdC5icmFpbikgJT4lCiAgZ3JvdXBfYnkoYnJvYWQsIGNlbGxUeXBlKSAlPiUKICBzdW1tYXJpc2UoIAogICAgZXhwMSA9IHF1YW50aWxlKHVwcGVyUV9leHAsIHQpLAogICAgZnhuMSA9IHF1YW50aWxlKGZ4bl9leHAsIHQpCiAgKSAlPiUgCiAgbXV0YXRlKAogICAgZXhwID0gZXhwMSsuMTQyLAogICAgZnhuID0gZnhuMSsuMTQyLAogICAgaHBhID0gJ25ldy5kYXQnCiAgKSAKCnNlYWFkLmJyb2FkICU+JSAKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluJywKICAgICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gJ25vdCcsCiAgICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAnZGVnJywKICAgICAgICBUIH4gJ290aGVyJykKICAgICAgKSAlPiUgCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JQogICMgZmlsdGVyKAogICMgICBmeG5fZXhwID49IHRocmVzaCRmeG5bIHdoaWNoKHRocmVzaCRjZWxsVHlwZSA9PSBjZWxsVHlwZSkgXSAlPiUgdW5pcXVlKCksCiAgIyAgIHVwcGVyUV9leHAgPj0gdGhyZXNoJGV4cFsgd2hpY2godGhyZXNoJGNlbGxUeXBlID09IGNlbGxUeXBlKSBdICU+JSB1bmlxdWUoKSwKICAjICAgLnByZXNlcnZlID0gVAogICMgKSAlPiUKICAjIHVuZ3JvdXAoKSAlPiUKICAKICBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gLTIuNSAqIGZ4bl9leHAgKyAyLjMpICU+JQoKICBnZ3Bsb3QoYWVzKGZ4bl9leHAsIHVwcGVyUV9leHAsIGdyb3VwID0gaHBhKSkrCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMi4zLCBzbG9wZSA9IC0yLjUpKwogICMgYW5ub3RhdGUoZ2VvbSA9ICd0ZXh0JywgeCA9IC42NSwgeSA9IDAsIGxhYmVsID0gJ3kgPSAtMi41eCArIDIuNScsIGhqdXN0ID0gMCkrCiAgZ2VvbV9wb2ludChkYXRhID0gdGhyZXNoLCBhZXMoeCA9IGZ4biwgeSA9IGV4cCksIHNpemUgPSAyLCBhbHBoYSA9IC41KSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nLCBhZXMoY29sb3IgPSBocGEpLCBsd2QgPSAuNSwgbHR5ID0gMikrCiAgbGFicyh5ID0gJ2V4cHJlc3Npb24nLCB4ID0gJ2ZyYWN0aW9uIGV4cHJlc3NpbmcnCiAgICAgICAjLCBzdWJ0aXRsZSA9IHBhc3RlMCgncGxvdHRpbmcgcXVhbnRpbGU6ICcsIHQpCiAgICAgICApKwogIGZhY2V0X3dyYXAofmJyb2FkLCBzY2FsZXMgPSAnZnJlZScpCgpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnNlYWFkLmJyb2FkICU+JSAKICBnZ3Bsb3QoYWVzKHVwcGVyUV9leHAsIGZ4bl9leHApKSsgCiAgZ2VvbV9iaW4yZChhZXMoZmlsbCA9IC4uY291bnQuLiApKSsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXModHJhbnMgPSAnbG9nMTAnLCBvcHRpb24gPSAnQScpKwogIGdndGl0bGUoJ25vIGZpbHRlcicpKwogIGZhY2V0X3dyYXAofmJyb2FkKQpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnRocmVzaCA9IHNlYWFkLmJyb2FkICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIG5vdC5icmFpbikgJT4lCiAgZ3JvdXBfYnkoYnJvYWQsIGNlbGxUeXBlKSAlPiUKICBzdW1tYXJpc2UoIAogICAgZXhwMSA9IHF1YW50aWxlKHVwcGVyUV9leHAsIHQpLAogICAgZnhuMSA9IHF1YW50aWxlKGZ4bl9leHAsIHQpCiAgKSAlPiUgCiAgbXV0YXRlKAogICAgZXhwID0gZXhwMSsuMTQyLAogICAgZnhuID0gZnhuMSsuMTQyLAogICAgaHBhID0gJ25ldy5kYXQnCiAgKSAKCnNlYWFkLmJyb2FkICU+JSAKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluJywKICAgICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICdkZWcnLAogICAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90JywKICAgICAgICBUIH4gJ290aGVyJykKICAgICAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgICAgIAoKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUKICAjIGZpbHRlcigKICAjICAgZnhuX2V4cCA+PSB0aHJlc2gkZnhuWyB3aGljaCh0aHJlc2gkY2VsbFR5cGUgPT0gY2VsbFR5cGUpIF0gJT4lIHVuaXF1ZSgpLAogICMgICB1cHBlclFfZXhwID49IHRocmVzaCRleHBbIHdoaWNoKHRocmVzaCRjZWxsVHlwZSA9PSBjZWxsVHlwZSkgXSAlPiUgdW5pcXVlKCksCiAgIyAgIC5wcmVzZXJ2ZSA9IFQKICAjICkgJT4lCiAgIyB1bmdyb3VwKCkgJT4lCgogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMykgJT4lCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogICMgbXV0YXRlKCBleHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAuOSksIAogICMgICAgICAgICBmeG4gPSBxdWFudGlsZShmeG5fZXhwLCAuOSkKICAjICAgICAgICAgKSAlPiUgCiAgIyBncm91cF9ieShjZWxsVHlwZSkgJT4lCiAgIyBmaWx0ZXIoICApICU+JQogICMgdW5ncm91cCgpICU+JSAKICAKICBtdXRhdGUoCiAgICBuID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsIGJyYWluLmdlbmVzKSksCiAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gbGVuZ3RoKGludGVyc2VjdChnZW5lLHRhZC5kZWcpKSwKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+IGxlbmd0aChpbnRlcnNlY3QoZ2VuZSxub3QuYnJhaW4pKSwKICAgICAgVCB+IGxlbmd0aCh1bmlxdWUoc2V0ZGlmZihnZW5lLCB1bmlvbih1bmlvbihicmFpbi5nZW5lcywgdGFkLmRlZyksIG5vdC5icmFpbikpKSkKICAgICAgKSkgJT4lCiAgZ2dwbG90KGFlcyh1cHBlclFfZXhwLCBmeG5fZXhwKSkrIAogIGdlb21fYmluMmQoYWVzKGZpbGwgPSAuLmNvdW50Li4gKSkrCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKHRyYW5zID0gJ2xvZzEwJywgb3B0aW9uID0gJ0EnKSsKICBmYWNldF93cmFwKH5icm9hZCkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0KCnNlYWFkLmJyb2FkICU+JSAKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgIGdlbmUgJWluJSBicmFpbi5nZW5lcyB+ICdicmFpbi5nZW5lcycsCiAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gJ3RhZC5kZWcnLAogICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gJ25vdC5icmFpbicsCiAgICAgIFQgfiAnb3RoZXInKQogICkgJT4lIAogIGZpbHRlcighaXMubmEoaHBhKSkgJT4lIAogIGdyb3VwX2J5KGhwYSkgJT4lIAogIG11dGF0ZSgKICAgIG4gPSBsZW5ndGgodW5pcXVlKGdlbmUpKSwKICAgIGhwYTEgPSBwYXN0ZTAoaHBhLCAnLCAnLCBuKQogICAgKSAlPiUgCiAgZ2dwbG90KGFlcyh1cHBlclFfZXhwLCBmeG5fZXhwKSkrIAogIGdlb21fYmluMmQoYWVzKGZpbGwgPSAuLmNvdW50Li4gKSkrCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKHRyYW5zID0gJ2xvZzEwJywgb3B0aW9uID0gJ0EnKSsKICBnZ3RpdGxlKCdubyBmaWx0ZXInKSsKICBmYWNldF9ncmlkKGJyb2FkfmhwYTEpCiAKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0KCnRocmVzaCA9IHNlYWFkLmJyb2FkICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIG5vdC5icmFpbikgJT4lCiAgZ3JvdXBfYnkoYnJvYWQsIGNlbGxUeXBlKSAlPiUKICBzdW1tYXJpc2UoIAogICAgZXhwMSA9IHF1YW50aWxlKHVwcGVyUV9leHAsIHQpLAogICAgZnhuMSA9IHF1YW50aWxlKGZ4bl9leHAsIHQpCiAgKSAlPiUgCiAgbXV0YXRlKAogICAgZXhwID0gZXhwMSsuMTQyLAogICAgZnhuID0gZnhuMSsuMTQyLAogICAgaHBhID0gJ25ldy5kYXQnCiAgKSAKCnNlYWFkLmJyb2FkICU+JSAKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluJywKICAgICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICd0YWQuZGVnJywKICAgICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gJ25vdC5icmFpbicsCiAgICAgICAgVCB+ICdvdGhlcicpCiAgICAgICkgJT4lIAogIGZpbHRlcighaXMubmEoaHBhKSkgJT4lICAgICAKCiAgIyBncm91cF9ieShjZWxsVHlwZSkgJT4lCiAgIyBmaWx0ZXIoCiAgIyAgIGZ4bl9leHAgPj0gdGhyZXNoJGZ4blsgd2hpY2godGhyZXNoJGNlbGxUeXBlID09IGNlbGxUeXBlKSBdICU+JSB1bmlxdWUoKSwKICAjICAgdXBwZXJRX2V4cCA+PSB0aHJlc2gkZXhwWyB3aGljaCh0aHJlc2gkY2VsbFR5cGUgPT0gY2VsbFR5cGUpIF0gJT4lIHVuaXF1ZSgpLAogICMgICAucHJlc2VydmUgPSBUCiAgIyApICU+JQogICMgdW5ncm91cCgpICU+JQogIAogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMykgJT4lCiAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gMiB8ICh1cHBlclFfZXhwID49IDEuMzMgJiBmeG5fZXhwID49IDAuMikgKSAlPiUKCiAgIyBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUKICAjIG11dGF0ZSh0b3BfZXhwID0gcXVhbnRpbGUodXBwZXJRX2V4cCwgMC43NSksCiAgIyAgICAgICAgdG9wX2Z4biA9IHF1YW50aWxlKGZ4bl9leHAsIDAuOTUpKSAlPiUKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+IHVuaXF1ZSh0b3BfZXhwW2hwYSA9PSAnbm90LmJyYWluJ10pICwKICAjICAgICAgICAgZnhuX2V4cCA+IHVuaXF1ZSh0b3BfZnhuW2hwYSA9PSAnbm90LmJyYWluJ10pICkgJT4lCiAgIyB1bmdyb3VwKCkgJT4lCiAgCiAgZ3JvdXBfYnkoaHBhKSAlPiUgCiAgbXV0YXRlKAogICAgbiA9IGxlbmd0aCh1bmlxdWUoZ2VuZSkpLAogICAgaHBhMSA9IHBhc3RlMChocGEsICcsICcsIG4pCiAgICApICU+JSAKICBnZ3Bsb3QoYWVzKHVwcGVyUV9leHAsIGZ4bl9leHApKSsgCiAgZ2VvbV9iaW4yZChhZXMoZmlsbCA9IC4uY291bnQuLiApKSsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXModHJhbnMgPSAnbG9nMTAnLCBvcHRpb24gPSAnQScpKwogIGdndGl0bGUoJ2ZpbHRlcmVkJykrCiAgZmFjZXRfZ3JpZChicm9hZH5ocGExKQogCmBgYAoKCiMjIyBmeG4gZXhwcmVzc2VkCmBgYHtyfQojIGFsc28gImJyYWluIGdlbmVzIjoKIyBzY29yZXMgJT4lIGZpbHRlcihpc1Njb3JlZF9vbWljcyA9PSAnWScsIE9taWNzU2NvcmUgPiAwKSAlPiUgcHVsbChHZW5lTmFtZSkgJT4lIHVuaXF1ZSgpCgpzZWFhZC5icm9hZCAlPiUgCiAgIyBmaWx0ZXIoaXMubmEoZ3JvdXApKSAlPiUgCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiBwYXN0ZTAoJ0hQQSBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSwgYnJhaW4uZ2VuZXMpKSwnIGdlbmVzKScpLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+IHBhc3RlMCgnVEFEIERFRyAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSx0YWQuZGVnKSksJyBnZW5lcyknKSwKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+IHBhc3RlMCgnSFBBIG5vdCBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSxub3QuYnJhaW4pKSwnIGdlbmVzKScpLAogICAgICBUIH4gcGFzdGUwKCdvdGhlciAobiA9ICcsIGxlbmd0aCh1bmlxdWUoc2V0ZGlmZihnZW5lLCB1bmlvbih1bmlvbihicmFpbi5nZW5lcywgdGFkLmRlZyksIG5vdC5icmFpbikpKSkgLCcgZ2VuZXMpJykKICAgICAgKQogICkgJT4lIAogIGZpbHRlcighaXMubmEoaHBhKSkgJT4lIAogIGdncGxvdChhZXMoIGZ4bl9leHAsIGZpbGwgPSBocGEpKSsKICBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhKSwgYWxwaGEgPSAuMSkrCiAgIyBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoJycpK3NjYWxlX2NvbG9yX2Rpc2NyZXRlKCcnKSsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93PTIpKSsKICBnZ2ZvcmNlOjpmYWNldF96b29tKHhsaW0gPSBjKDAsLjI1KSwgeWxpbSA9IGMoMCw1KSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcpCmBgYAoKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9MTN9CiMgc2VhYWQuYnJvYWQgJT4lIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUgc3VtbWFyaXNlKG1uID0gbWVkaWFuKGZyYWN0aW9uX2V4cHJlc3NlZCkpCgpzZWFhZC5icm9hZCAlPiUgCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiBwYXN0ZTAoJ0hQQSBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSwgYnJhaW4uZ2VuZXMpKSwnIGdlbmVzKScpLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+IHBhc3RlMCgnVEFEIERFRyAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSx0YWQuZGVnKSksJyBnZW5lcyknKSwKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+IHBhc3RlMCgnSFBBIG5vdCBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSxub3QuYnJhaW4pKSwnIGdlbmVzKScpLAogICAgICBUIH4gcGFzdGUwKCdvdGhlciAobiA9ICcsIGxlbmd0aCh1bmlxdWUoc2V0ZGlmZihnZW5lLCB1bmlvbih1bmlvbihicmFpbi5nZW5lcywgdGFkLmRlZyksIG5vdC5icmFpbikpKSkgLCcgZ2VuZXMpJykKICAgICAgKQogICkgJT4lIAogIGdyb3VwX2J5KGNlbGxUeXBlLCBocGEpICU+JSAKICBtdXRhdGUodG9wX2V4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIDAuNzUpLAogICAgICAgICB0b3BfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgMC43NSkpICU+JSAKICBnZ3Bsb3QoLiwgYWVzKGZ4bl9leHAsIGNlbGxUeXBlLCBmaWxsID0gaHBhKSkgKyAKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICd3aWR0aCcsIGRyYXdfcXVhbnRpbGVzID0gYyguNSkpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gdG9wX2Z4biwgY29sb3IgPSBocGEpKSsKICAjIHN0YXRfc3VtbWFyeShmdW4gPSBmdW5jdGlvbih4KSBxdWFudGlsZSh4LDAuNSksIGdlb209InBvaW50Iiwgc2l6ZT0yLCBjb2xvcj0icmVkIiwgcG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIGdnZm9yY2U6OmZhY2V0X3pvb20oeGxpbSA9IGMoMCwwLjA4KSwgaG9yaXpvbnRhbCA9IEYpCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsMC4yNSkpCgpgYGAKCmBgYHtyfQojIGFsc28gImJyYWluIGdlbmVzIjoKIyBzY29yZXMgJT4lIGZpbHRlcihpc1Njb3JlZF9vbWljcyA9PSAnWScsIE9taWNzU2NvcmUgPiAwKSAlPiUgcHVsbChHZW5lTmFtZSkgJT4lIHVuaXF1ZSgpCgpzZWFhZC5icm9hZCAlPiUgCiAgIyBmaWx0ZXIoaXMubmEoZ3JvdXApKSAlPiUgCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiBwYXN0ZTAoJ0hQQSBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSwgYnJhaW4uZ2VuZXMpKSwnIGdlbmVzKScpLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+IHBhc3RlMCgnVEFEIERFRyAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSx0YWQuZGVnKSksJyBnZW5lcyknKSwKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+IHBhc3RlMCgnSFBBIG5vdCBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSxub3QuYnJhaW4pKSwnIGdlbmVzKScpLAogICAgICBUIH4gcGFzdGUwKCdvdGhlciAobiA9ICcsIGxlbmd0aCh1bmlxdWUoc2V0ZGlmZihnZW5lLCB1bmlvbih1bmlvbihicmFpbi5nZW5lcywgdGFkLmRlZyksIG5vdC5icmFpbikpKSkgLCcgZ2VuZXMpJykKICAgICAgKQogICkgJT4lIAogIGZpbHRlcighaXMubmEoaHBhKSkgJT4lIAogIGdncGxvdChhZXMoIGZ4bl9leHAsIGZpbGwgPSBocGEpKSsKICAjIGdlb21fZGVuc2l0eShhZXMoY29sb3IgPSBocGEpLCBhbHBoYSA9IC4xKSsKICBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoJycpK3NjYWxlX2NvbG9yX2Rpc2NyZXRlKCcnKSsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93PTIpKSsKICBnZ2ZvcmNlOjpmYWNldF96b29tKHhsaW0gPSBjKDAsLjI1KSwgeWxpbSA9IGMoMCwxZTUpKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykKYGBgCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQuYnJvYWQgJT4lIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4uZ2VuZXMnLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICd0YWQuZGVnJywKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QuYnJhaW4nLAogICAgICBUIH4gJ290aGVyJykKICApICU+JSAKICBmaWx0ZXIoIWlzLm5hKGhwYSkpICU+JSAKCiAgIyBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUgCiAgIyBtdXRhdGUodG9wX2V4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIDAuNzUpLAogICMgICAgICAgIHRvcF9meG4gPSBxdWFudGlsZShmeG5fZXhwLCAwLjk1KSkgJT4lIAogICMgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPiB1bmlxdWUodG9wX2V4cFtocGEgPT0gJ25vdC5icmFpbiddKSAsCiAgIyAgICAgICAgIGZ4bl9leHAgPiB1bmlxdWUodG9wX2Z4bltocGEgPT0gJ25vdC5icmFpbiddKSApICU+JSAKICAjIHVuZ3JvdXAoKSAlPiUgCiAgCiAgZmlsdGVyKCB1cHBlclFfZXhwID49IC0yLjUgKiBmeG5fZXhwICsgMi4zKSAlPiUKICAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQoKICBncm91cF9ieShocGEpICU+JSAKICBtdXRhdGUoCiAgICBuID0gbGVuZ3RoKHVuaXF1ZShnZW5lKSksCiAgICBocGExID0gcGFzdGUwKGhwYSwgJywgJywgbikKICAgICkgJT4lIAogIAogIGdncGxvdChhZXMoIGZ4bl9leHAsIGZpbGwgPSBocGExKSkrCiAgIyBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhMSksIGFscGhhID0gLjEpKwogIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gJ2RvZGdlJykrCiAgIyBzY2FsZV95X2xvZzEwKCkrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgnJykrc2NhbGVfY29sb3JfZGlzY3JldGUoJycpKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKG5yb3c9MikpKwogIGdnZm9yY2U6OmZhY2V0X3pvb20oeGxpbSA9IGMoMCwuMjUpLCB5bGltID0gYygwLDFlNSkpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnKQpgYGAKCgoKYGBge3J9CiMgYWxzbyAiYnJhaW4gZ2VuZXMiOgojIHNjb3JlcyAlPiUgZmlsdGVyKGlzU2NvcmVkX29taWNzID09ICdZJywgT21pY3NTY29yZSA+IDApICU+JSBwdWxsKEdlbmVOYW1lKSAlPiUgdW5pcXVlKCkKCnNlYWFkLmJyb2FkICU+JSAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluLmdlbmVzJywKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAndGFkLmRlZycsCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgVCB+ICdvdGhlcicpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogICMgbXV0YXRlKHRvcF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjc1KSwKICAjICAgICAgICB0b3BfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgMC45NSkpICU+JSAKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUgIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID4gdW5pcXVlKHRvcF9leHBbaHBhID09ICdub3QuYnJhaW4nXSkgLAogICMgICAgICAgICBmeG5fZXhwID4gdW5pcXVlKHRvcF9meG5baHBhID09ICdub3QuYnJhaW4nXSkgKSAlPiUgCiAgIyB1bmdyb3VwKCkgJT4lIAogIAogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMykgJT4lCiAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gMiB8ICh1cHBlclFfZXhwID49IDEuMzMgJiBmeG5fZXhwID49IDAuMikgKSAlPiUKCiAgZ3JvdXBfYnkoaHBhKSAlPiUgCiAgbXV0YXRlKAogICAgbiA9IGxlbmd0aCh1bmlxdWUoZ2VuZSkpLAogICAgaHBhMSA9IHBhc3RlMChocGEsICcsICcsIG4pCiAgICApICU+JSAKICAKICBnZ3Bsb3QoYWVzKCBmeG5fZXhwLCBjb2xvciA9IGhwYTEpKSsKICBnZW9tX2RlbnNpdHkoIGFscGhhID0gLjEpKwogICMgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjIsIGx0eSA9IDIpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoJycpK3NjYWxlX2NvbG9yX2Rpc2NyZXRlKCcnKSsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93PTIpKSsKICBnZ2ZvcmNlOjpmYWNldF96b29tKHhsaW0gPSBjKDAsLjI1KSwgeWxpbSA9IGMoMCwxLjcpKSsjCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcpCmBgYApgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xM30KIyBzZWFhZC5icm9hZCAlPiUgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSBzdW1tYXJpc2UobW4gPSBtZWRpYW4oZnJhY3Rpb25fZXhwcmVzc2VkKSkKCnNlYWFkLmJyb2FkICU+JSAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluLmdlbmVzJywKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAndGFkLmRlZycsCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgVCB+ICdvdGhlcicpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogICMgbXV0YXRlKHRvcF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjc1KSwKICAjICAgICAgICB0b3BfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgMC45NSkpICU+JSAKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUgIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID4gdW5pcXVlKHRvcF9leHBbaHBhID09ICdub3QuYnJhaW4nXSkgLAogICMgICAgICAgICBmeG5fZXhwID4gdW5pcXVlKHRvcF9meG5baHBhID09ICdub3QuYnJhaW4nXSkgKSAlPiUgCiAgIyB1bmdyb3VwKCkgJT4lIAoKICBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gLTIuNSAqIGZ4bl9leHAgKyAyLjMpICU+JQogIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCgogIGdyb3VwX2J5KGhwYSkgJT4lIAogIG11dGF0ZSgKICAgIG4gPSBsZW5ndGgodW5pcXVlKGdlbmUpKSwKICAgIGhwYTEgPSBwYXN0ZTAoaHBhLCAnLCAnLCBuKQogICAgKSAlPiUgCgogIGdncGxvdCguLCBhZXMoZnhuX2V4cCwgY2VsbFR5cGUsIGZpbGwgPSBocGExKSkgKyAKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICd3aWR0aCcsIGRyYXdfcXVhbnRpbGVzID0gYyguNSksIHRyaW0gPSBGKSArCiAgIyBnZW9tX3BvaW50KGFlcyh4ID0gdG9wX2Z4biwgY29sb3IgPSBocGEpKSsKICAjIHN0YXRfc3VtbWFyeShmdW4gPSBmdW5jdGlvbih4KSBxdWFudGlsZSh4LDAuNSksIGdlb209InBvaW50Iiwgc2l6ZT0yLCBjb2xvcj0icmVkIiwgcG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIGdnZm9yY2U6OmZhY2V0X3pvb20oeGxpbSA9IGMoMCwwLjA4KSwgaG9yaXpvbnRhbCA9IEYpCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsMSkpCgpgYGAKCgojIyMgYXZnIGV4cHJlc3Npb24KCmBgYHtyfQojIGFsc28gImJyYWluIGdlbmVzIjoKIyBzY29yZXMgJT4lIGZpbHRlcihpc1Njb3JlZF9vbWljcyA9PSAnWScsIE9taWNzU2NvcmUgPiAwKSAlPiUgcHVsbChHZW5lTmFtZSkgJT4lIHVuaXF1ZSgpCgpzZWFhZC5icm9hZCAlPiUgCiAgIyBmaWx0ZXIoaXMubmEoZ3JvdXApKSAlPiUgCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiBwYXN0ZTAoJ0hQQSBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSwgYnJhaW4uZ2VuZXMpKSwnIGdlbmVzKScpLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+IHBhc3RlMCgnVEFEIERFRyAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSx0YWQuZGVnKSksJyBnZW5lcyknKSwKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+IHBhc3RlMCgnSFBBIG5vdCBicmFpbiAobiA9ICcsIGxlbmd0aChpbnRlcnNlY3QoZ2VuZSxub3QuYnJhaW4pKSwnIGdlbmVzKScpLAogICAgICBUIH4gcGFzdGUwKCdvdGhlciAobiA9ICcsIGxlbmd0aCh1bmlxdWUoc2V0ZGlmZihnZW5lLCB1bmlvbih1bmlvbihicmFpbi5nZW5lcywgdGFkLmRlZyksIG5vdC5icmFpbikpKSkgLCcgZ2VuZXMpJykKICAgICAgKQogICkgJT4lIAogIGZpbHRlcighaXMubmEoaHBhKSkgJT4lIAogIGdncGxvdChhZXMoICh1cHBlclFfZXhwKSwgZmlsbCA9IGhwYSkpKwogIGdlb21fZGVuc2l0eShhZXMoY29sb3IgPSBocGEpLCBhbHBoYSA9IC4xKSsKICAjIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gJ2RvZGdlJykrCiAgIyBzY2FsZV95X2xvZzEwKCkrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgnJykrc2NhbGVfY29sb3JfZGlzY3JldGUoJycpKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKG5yb3c9MikpKwogIGdnZm9yY2U6OmZhY2V0X3pvb20oeGxpbSA9IGMoMCwyKSwgeWxpbSA9IGMoMCwxLjMpICkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcpCgpgYGAKCmBgYHtyIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTEzLCB3YXJuaW5nPUZBTFNFfQojIHNlYWFkLmJyb2FkICU+JSBncm91cF9ieShjZWxsVHlwZSkgJT4lIHN1bW1hcmlzZShtbiA9IG1lZGlhbihmcmFjdGlvbl9leHByZXNzZWQpKQoKc2VhYWQuYnJvYWQgJT4lIAogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gcGFzdGUwKCdIUEEgYnJhaW4gKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsIGJyYWluLmdlbmVzKSksJyBnZW5lcyknKSwKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiBwYXN0ZTAoJ1RBRCBERUcgKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsdGFkLmRlZykpLCcgZ2VuZXMpJyksCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiBwYXN0ZTAoJ0hQQSBub3QgYnJhaW4gKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsbm90LmJyYWluKSksJyBnZW5lcyknKSwKICAgICAgVCB+IHBhc3RlMCgnb3RoZXIgKG4gPSAnLCBsZW5ndGgodW5pcXVlKHNldGRpZmYoZ2VuZSwgdW5pb24odW5pb24oYnJhaW4uZ2VuZXMsIHRhZC5kZWcpLCBub3QuYnJhaW4pKSkpICwnIGdlbmVzKScpCiAgICAgICkKICApICU+JSAKICBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUgCiAgbXV0YXRlKHRvcF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjc1KSwKICAgICAgICAgdG9wX2Z4biA9IHF1YW50aWxlKGZ4bl9leHAsIDAuNzUpKSAlPiUgCiAgZ2dwbG90KC4sIGFlcyh1cHBlclFfZXhwLCBjZWxsVHlwZSwgZmlsbCA9IGhwYSkpICsgCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAnd2lkdGgnLCBkcmF3X3F1YW50aWxlcyA9IGMoLjUpKSArCiAgIyBnZW9tX3BvaW50KGFlcyh4ID0gdG9wX2V4cCwgY29sb3IgPSBocGEpKSsKICAjIHN0YXRfc3VtbWFyeShmdW4gPSBmdW5jdGlvbih4KSBxdWFudGlsZSh4LDAuNSksIGdlb209InBvaW50Iiwgc2l6ZT0yLCBjb2xvcj0icmVkIiwgcG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIGdnZm9yY2U6OmZhY2V0X3pvb20oeGxpbSA9IGMoMCwwLjA4KSwgaG9yaXpvbnRhbCA9IEYpCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsNikpCgpgYGAKCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQuYnJvYWQgJT4lIAogICMgZmlsdGVyKGlzLm5hKGdyb3VwKSkgJT4lIAogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gcGFzdGUwKCdIUEEgYnJhaW4gKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsIGJyYWluLmdlbmVzKSksJyBnZW5lcyknKSwKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiBwYXN0ZTAoJ1RBRCBERUcgKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsdGFkLmRlZykpLCcgZ2VuZXMpJyksCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiBwYXN0ZTAoJ0hQQSBub3QgYnJhaW4gKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsbm90LmJyYWluKSksJyBnZW5lcyknKSwKICAgICAgVCB+IHBhc3RlMCgnb3RoZXIgKG4gPSAnLCBsZW5ndGgodW5pcXVlKHNldGRpZmYoZ2VuZSwgdW5pb24odW5pb24oYnJhaW4uZ2VuZXMsIHRhZC5kZWcpLCBub3QuYnJhaW4pKSkpICwnIGdlbmVzKScpCiAgICAgICkKICApICU+JSAKICAjIGdyb3VwX2J5KGNlbGxUeXBlLCBocGEpICU+JSAKICAjIG11dGF0ZShtZF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjUpLAogICMgICAgICAgIGZpdmVwY3RfZXhwID0gcXVhbnRpbGUodXBwZXJRX2V4cCwgMC45NSksIAogICMgICAgICAgIGZpdmVwY3RfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgLjUpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCiAgZ2dwbG90KGFlcyggKHVwcGVyUV9leHApLCBmaWxsID0gaHBhKSkrCiAgIyBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhKSwgYWxwaGEgPSAuMSkrCiAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCcnKStzY2FsZV9jb2xvcl9kaXNjcmV0ZSgnJykrCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDIpLCB5bGltID0gYygwLDMuNWU0KSApKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnKQoKYGBgCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQuYnJvYWQgJT4lIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4uZ2VuZXMnLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICd0YWQuZGVnJywKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QuYnJhaW4nLAogICAgICBUIH4gJ290aGVyJykKICApICU+JSAKICBmaWx0ZXIoIWlzLm5hKGhwYSkpICU+JSAKCiAgIyBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUgCiAgIyBtdXRhdGUodG9wX2V4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIDAuNzUpLAogICMgICAgICAgIHRvcF9meG4gPSBxdWFudGlsZShmeG5fZXhwLCAwLjk1KSkgJT4lIAogICMgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPiB1bmlxdWUodG9wX2V4cFtocGEgPT0gJ25vdC5icmFpbiddKSAsCiAgIyAgICAgICAgIGZ4bl9leHAgPiB1bmlxdWUodG9wX2Z4bltocGEgPT0gJ25vdC5icmFpbiddKSApICU+JSAKICAjIHVuZ3JvdXAoKSAlPiUgCiAgCiAgZmlsdGVyKCB1cHBlclFfZXhwID49IC0yLjUgKiBmeG5fZXhwICsgMi4zKSAlPiUKICAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQoKICBncm91cF9ieShocGEpICU+JSAKICBtdXRhdGUoCiAgICBuID0gbGVuZ3RoKHVuaXF1ZShnZW5lKSksCiAgICBocGExID0gcGFzdGUwKGhwYSwgJywgJywgbikKICAgICkgJT4lIAogIAogIGdncGxvdChhZXMoIHVwcGVyUV9leHAsIGZpbGwgPSBocGExKSkrCiAgIyBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhKSwgYWxwaGEgPSAuMSkrCiAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCcnKStzY2FsZV9jb2xvcl9kaXNjcmV0ZSgnJykrCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDIpLCB5bGltID0gYygwLDMuNWU0KSApKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnKQpgYGAKCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQuYnJvYWQgJT4lIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4uZ2VuZXMnLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICd0YWQuZGVnJywKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QuYnJhaW4nLAogICAgICBUIH4gJ290aGVyJykKICApICU+JSAKICBmaWx0ZXIoIWlzLm5hKGhwYSkpICU+JSAKCiAgIyBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUgCiAgIyBtdXRhdGUodG9wX2V4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIDAuNzUpLAogICMgICAgICAgIHRvcF9meG4gPSBxdWFudGlsZShmeG5fZXhwLCAwLjk1KSkgJT4lIAogICMgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPiB1bmlxdWUodG9wX2V4cFtocGEgPT0gJ25vdC5icmFpbiddKSAsCiAgIyAgICAgICAgIGZ4bl9leHAgPiB1bmlxdWUodG9wX2Z4bltocGEgPT0gJ25vdC5icmFpbiddKSApICU+JSAKICAjIHVuZ3JvdXAoKSAlPiUgCgogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMykgJT4lCiAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gMiB8ICh1cHBlclFfZXhwID49IDEuMzMgJiBmeG5fZXhwID49IDAuMikgKSAlPiUKCiAgZ3JvdXBfYnkoaHBhKSAlPiUgCiAgbXV0YXRlKAogICAgbiA9IGxlbmd0aCh1bmlxdWUoZ2VuZSkpLAogICAgaHBhMSA9IHBhc3RlMChocGEsICcsICcsIG4pCiAgICApICU+JSAKCiAgZ2dwbG90KGFlcyggdXBwZXJRX2V4cCwgY29sb3IgPSBocGExICkpKwogIGdlb21fZGVuc2l0eSggYWxwaGEgPSAuMSkrCiAgIyBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoJycpK3NjYWxlX2NvbG9yX2Rpc2NyZXRlKCcnKSsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDIpLCB5bGltID0gYygwLDEuMykgKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykKYGBgCgpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xMywgd2FybmluZz1GQUxTRX0KIyBzZWFhZC5icm9hZCAlPiUgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSBzdW1tYXJpc2UobW4gPSBtZWRpYW4oZnJhY3Rpb25fZXhwcmVzc2VkKSkKCnNlYWFkLmJyb2FkICU+JSAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluLmdlbmVzJywKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAndGFkLmRlZycsCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgVCB+ICdvdGhlcicpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogICMgbXV0YXRlKHRvcF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjc1KSwKICAjICAgICAgICB0b3BfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgMC45NSkpICU+JSAKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUgIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID4gdW5pcXVlKHRvcF9leHBbaHBhID09ICdub3QuYnJhaW4nXSkgLAogICMgICAgICAgICBmeG5fZXhwID4gdW5pcXVlKHRvcF9meG5baHBhID09ICdub3QuYnJhaW4nXSkgKSAlPiUgCiAgIyB1bmdyb3VwKCkgJT4lIAoKICBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gLTIuNSAqIGZ4bl9leHAgKyAyLjMpICU+JQogIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCgogIGdyb3VwX2J5KGhwYSkgJT4lIAogIG11dGF0ZSgKICAgIG4gPSBsZW5ndGgodW5pcXVlKGdlbmUpKSwKICAgIGhwYTEgPSBwYXN0ZTAoaHBhLCAnLCAnLCBuKQogICAgKSAlPiUgCiAgCiAgZ2dwbG90KC4sIGFlcyh1cHBlclFfZXhwLCBjZWxsVHlwZSwgZmlsbCA9IGhwYTEpKSArIAogIGdlb21fdmlvbGluKHNjYWxlID0gJ3dpZHRoJywgZHJhd19xdWFudGlsZXMgPSBjKC41KSwgdHJpbSA9IEYpICsKICAjIGdlb21fcG9pbnQoYWVzKHggPSB0b3BfZXhwLCBjb2xvciA9IGhwYSkpKwogICMgc3RhdF9zdW1tYXJ5KGZ1biA9IGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsMC41KSwgZ2VvbT0icG9pbnQiLCBzaXplPTIsIGNvbG9yPSJyZWQiLCBwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDAuMDgpLCBob3Jpem9udGFsID0gRikKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCw2KSkKCmBgYAoKCiMjIyBjZWxsdHlwZS1zcGVjaWZpYyBnZW5lcwpgYGB7cn0KIyBNY0tlbnppZSBicmFpbiBjZWxsIHR5cGUgc3BlY2ZpYyBleHByZXNzaW9uIFBNSUQgMjk4OTIwMDYKdXJsPSdodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM1OTk1ODAzL2Jpbi80MTU5OF8yMDE4XzI3MjkzX01PRVNNMl9FU00ueGxzeCcKaHR0cjo6R0VUKHVybCwgaHR0cjo6d3JpdGVfZGlzayh0ZiA8LSB0ZW1wZmlsZShmaWxlZXh0ID0gIi54bHN4IikpKQoKIyByZWFkeGw6OmV4Y2VsX3NoZWV0cyh0ZikKIyBbMV0gInRvcF9hbGxfZW5yaWNoIiAgICAgICAgInRvcF9odW1hbl9lbnJpY2giICAgICAgInRvcF9tb3VzZV9lbnJpY2giICAgICAKIyBbNF0gInRvcF9hbGxfZXhwcmVzc2lvbiIgICAgInRvcF9odW1hbl9leHByZXNzaW9uIiAgInRvcF9tb3VzZV9leHByZXNzaW9uIiAKIyBbN10gInRvcF9hbGxfc3BlY2lmaWNpdHkiICAgInRvcF9odW1hbl9zcGVjaWZpY2l0eSIgInRvcF9tb3VzZV9zcGVjaWZpY2l0eSIKCmN0X3NwZWMgPSByZWFkeGw6OnJlYWRfeGxzeCh0ZixzaGVldCA9ICd0b3BfYWxsX2VucmljaCcsIHNraXAgPSAxKQoKY3Rfc3BlYyAlPiUgCiAgZ3JvdXBfYnkoQ2VsbHR5cGUpICU+JSAKICBzdW1tYXJpc2UobW4gPSBtZWRpYW4oZ3JhbmRfbWVhbiksIHNkID0gc2QoZ3JhbmRfbWVhbiksIG1uX3NkID0gbW4rc2QpICU+JSAKICBhcnJhbmdlKGRlc2MobW5fc2QpKQoKZHVwcyA9IGN0X3NwZWMkZ2VuZVt3aGljaChkdXBsaWNhdGVkKGN0X3NwZWMkZ2VuZSkpXSAlPiUgdW5pcXVlKCkgCmBgYAoKYGBge3J9CmN0X3NwZWMgJT4lIAogIGZpbHRlcighKGdlbmUgJWluJSBkdXBzKSkgJT4lIAogIGdyb3VwX2J5KENlbGx0eXBlKSAlPiUgCiAgbXV0YXRlKG1uID0gbWVkaWFuKGdyYW5kX21lYW4pLCBzZCA9IHNkKGdyYW5kX21lYW4pLCBtbl9zZCA9IG1uK3NkKSAlPiUgCiAgZ2dwbG90KGFlcyhncmFuZF9tZWFuLCBjb2xvciA9IENlbGx0eXBlKSkrCiAgZ2VvbV9kZW5zaXR5KCkrCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1uX3NkLCBjb2xvciA9IENlbGx0eXBlKSkKCmBgYAoKCmBgYHtyIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTMsIHdhcm5pbmc9RkFMU0V9CiMgc2VhYWQuYnJvYWQgPSByZWFkX2NzdignL3Byb2plY3RzL2NhcnRlci1sYWIvY2FyeWcvc2VhQUQvZGF0YS9zZWFBRF9icm9hZF9zdW1tYXJ5Q291bnRzLmNzdicpCiMgc2VhYWQuYnJvYWQgPSByZWFkX2NzdignL3Byb2plY3RzL2NhcnRlci1sYWIvY2FyeWcvc2VhQUQvZGF0YS9zZWFBRF9icm9hZF91cHBlclFfc3VtbWFyeUNvdW50cy5jc3YnKQoKY3Rfc3BlYyAlPiUgCiAgZmlsdGVyKCEoZ2VuZSAlaW4lIGR1cHMpKSAlPiUgCiAgZ3JvdXBfYnkoQ2VsbHR5cGUpICU+JSAKICBtdXRhdGUobW4gPSBtZWRpYW4oZ3JhbmRfbWVhbiksIHNkID0gc2QoZ3JhbmRfbWVhbiksIG1uX3NkID0gbW4rc2QpICU+JSAKICBmaWx0ZXIoZ3JhbmRfbWVhbiA+IG1uX3NkKSAlPiUgCiAgc2VsZWN0KGdlbmUsIENlbGx0eXBlKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgaW5uZXJfam9pbihzZWFhZC5icm9hZCwgLiwgYnkgPSAnZ2VuZScpICU+JSAKCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gLTIuNSAqIGZ4bl9leHAgKyAyLjUpICU+JQoKICBnZ3Bsb3QoLiwgYWVzKGJyb2FkLCB1cHBlclFfZXhwLCBmaWxsID0gQ2VsbHR5cGUpKSArIAogIGdlb21fdmlvbGluKHNjYWxlID0gJ3dpZHRoJywgZHJhd19xdWFudGlsZXMgPSBjKC41KSwgdHJpbSA9IEYpIAoKYGBgCgpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD0zfQojIHNlYWFkLmJyb2FkID0gcmVhZF9jc3YoJy9wcm9qZWN0cy9jYXJ0ZXItbGFiL2NhcnlnL3NlYUFEL2RhdGEvc2VhQURfYnJvYWRfc3VtbWFyeUNvdW50cy5jc3YnKQojIHNlYWFkLmJyb2FkID0gcmVhZF9jc3YoJy9wcm9qZWN0cy9jYXJ0ZXItbGFiL2NhcnlnL3NlYUFEL2RhdGEvc2VhQURfYnJvYWRfdXBwZXJRX3N1bW1hcnlDb3VudHMuY3N2JykKCmN0X3NwZWMgJT4lIAogIGZpbHRlcighKGdlbmUgJWluJSBkdXBzKSkgJT4lIAogIGdyb3VwX2J5KENlbGx0eXBlKSAlPiUgCiAgbXV0YXRlKG1uID0gbWVkaWFuKGdyYW5kX21lYW4pLCBzZCA9IHNkKGdyYW5kX21lYW4pLCBtbl9zZCA9IG1uK3NkKSAlPiUgCiAgZmlsdGVyKGdyYW5kX21lYW4gPiBtbl9zZCkgJT4lIAogIHNlbGVjdChnZW5lLCBDZWxsdHlwZSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGlubmVyX2pvaW4oc2VhYWQuYnJvYWQsIC4sIGJ5ID0gJ2dlbmUnKSAlPiUgCgogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMykgJT4lCgogIGdncGxvdCguLCBhZXMoYnJvYWQsIHVwcGVyUV9leHAsIGZpbGwgPSBDZWxsdHlwZSkpICsgCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAnd2lkdGgnLCBkcmF3X3F1YW50aWxlcyA9IGMoLjUpLCB0cmltID0gRikgCgpgYGAKCiMjIHN1cGVydHlwZQpgYGB7cn0Kc2VhYWQgPSByZWFkX2NzdignL3Byb2plY3RzL2NhcnRlci1sYWIvY2FyeWcvc2VhQUQvZGF0YS9zZWFBRF91cHBlclFfc3VtbWFyeUNvdW50cy5jc3YnKQpgYGAKIyMjIGJvdGggZGltZW5zaW9ucwoKYGBge3J9CnQgPSAuOQoKdG1wID0gc2VhYWQgJT4lIAoKICAjIGZpbHRlcihnZW5lICVpbiUgbm90LmJyYWluKSAlPiUgCiAgIyBtdXRhdGUoaHBhID0gJ25vdCcpICU+JSAKCiAgbXV0YXRlKAogICAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4nLAogICAgICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QnLAogICAgICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAnZGVnJywKICAgICAgICAgIFQgfiAnb3RoZXInCiAgICAgICkKICApICU+JQoKICBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUgCiAgc3VtbWFyaXNlKCAKICAgIGV4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIHQpLCAKICAgIGZ4biA9IHF1YW50aWxlKGZ4bl9leHAsIHQpCiAgICApIAoKIyBiaW5kX3Jvd3MoCiMgICAgIHRtcCwgCiMgICAgIHRtcCAlPiUgZmlsdGVyKGhwYSA9PSAnbm90JykgJT4lIG11dGF0ZShleHAgPSBleHAgKyAuMTQyLCBmeG4gPSBmeG4gKyAuMTQyLCBocGEgPSAnbmV3JykKIyAgICkgJT4lIAp0bXAgJT4lIAogIGdncGxvdChhZXMoZnhuLCBleHAsIGdyb3VwID0gaHBhKSkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgY29sb3IgPSAnZ3JleTIwJywgbHdkID0gLjUsIGx0eSA9IDIpKwogICMgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMS41Mjk0LCBzbG9wZSA9IC0yLjU2MjU2OSkrCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMi4zLCBzbG9wZSA9IC0yLjUpKwogIGFubm90YXRlKGdlb20gPSAndGV4dCcsIHggPSAuNjUsIHkgPSAwLCBsYWJlbCA9ICd5ID0gLTIuNXggKyAyLjMnLCBoanVzdCA9IDApKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY2VsbFR5cGUsIHNoYXBlID0gaHBhKSwgc2l6ZSA9IDIsIGFscGhhID0gLjUpKwogIGd1aWRlcyhjb2xvciA9ICdub25lJykrCiAgbGFicyh5ID0gJ3F1YW50aWxlIGV4cHJlc3Npb24nLCB4ID0gJ3F1YW50aWxlIGZyYWN0aW9uIGV4cHJlc3NpbmcnLAogICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoJ3Bsb3R0aW5nIHF1YW50aWxlOiAnLCB0KSkKCmBgYAoKCmBgYHtyfQp0ID0gLjkKCnNlYWFkICU+JSAKICAKICAjIGZpbHRlcihnZW5lICVpbiUgbm90LmJyYWluKSAlPiUgCiAgIyBtdXRhdGUoaHBhID0gJ25vdCcpICU+JSAKCiAgbXV0YXRlKAogICAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4nLAogICAgICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QnLAogICAgICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAnZGVnJywKICAgICAgICAgIFQgfiAnb3RoZXInCiAgICAgICkKICApICU+JQogIGZpbHRlcihocGEgPT0gJ25vdCcpICU+JQoKICBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUKICBzdW1tYXJpc2UoIGV4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIHQpLCAKICAgICAgICAgICAgIGZ4biA9IHF1YW50aWxlKGZ4bl9leHAsIHQpCiAgICAgICAgICAgICApICU+JSAKICBsbShleHB+ZnhuLCBkYXRhID0gLikgJT4lIAogIGJyb29tOjp0aWR5KCkKYGBgCgpgYGB7cn0KeCA9IG1hcF9kZnIoCiAgICBzZXEoMS41LDMsLjEpLAogICAgfnsKICAgICAgICBzZWFhZCAlPiUgCiAgICAgICAgICAgIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIC54KSAlPiUgCiAgICAgICAgICAgIHN1bW1hcmlzZSgKICAgICAgICAgICAgICAgIGludCA9IC54LAogICAgICAgICAgICAgICAgbi5icmFpbiA9IGxlbmd0aChpbnRlcnNlY3QoZ2VuZSwgYnJhaW4uZ2VuZXMgKSksCiAgICAgICAgICAgICAgICBuLm5vdCA9IGxlbmd0aChpbnRlcnNlY3QoZ2VuZSxub3QuYnJhaW4pKSwKICAgICAgICAgICAgICAgIG4uZGVnID0gbGVuZ3RoKGludGVyc2VjdChnZW5lLHRhZC5kZWcpKSwKICAgICAgICAgICAgICAgIG4ub3RoZXIgPSBsZW5ndGgodW5pcXVlKHNldGRpZmYoZ2VuZSwgdW5pb24odW5pb24oYnJhaW4uZ2VuZXMsIHRhZC5kZWcpLCBub3QuYnJhaW4pKSkpLAogICAgICAgICAgICAgICAgZGlmZi5iID0gKG4uYnJhaW4gLSBuLm5vdCksCiAgICAgICAgICAgICAgICBwY3QuYiA9IDEwMCooZGlmZi5iL24uYnJhaW4pLAogICAgICAgICAgICAgICAgZGlmZi5kID0gbi5kZWcgLSBuLm5vdCwKICAgICAgICAgICAgICAgIHBjdC5kID0gMTAwKihkaWZmLmQvbi5icmFpbikKICAgICAgICAgICAgKQogICAgfQopICU+JSAKICBhcnJhbmdlKGRlc2MoZGlmZi5iKSwgZGVzYyhwY3QuZCkpOwoKcXBsb3QoeCRpbnQsIHgkZGlmZi5iLCBnZW9tID0gJ2xpbmUnKQoKRFQ6OmRhdGF0YWJsZSh4KQpgYGAKCmBgYHtyfQp0ID0gLjkKCnRocmVzaCA9IHNlYWFkICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIG5vdC5icmFpbikgJT4lCiAgZ3JvdXBfYnkoYnJvYWQsIGNlbGxUeXBlKSAlPiUKICBzdW1tYXJpc2UoIAogICAgZXhwMSA9IHF1YW50aWxlKHVwcGVyUV9leHAsIHQpLAogICAgZnhuMSA9IHF1YW50aWxlKGZ4bl9leHAsIHQpCiAgKSAlPiUgCiAgbXV0YXRlKAogICAgZXhwID0gZXhwMSsuMTQyLAogICAgZnhuID0gZnhuMSsuMTQyLAogICAgaHBhID0gJ25ldy5kYXQnCiAgKSAKCnNlYWFkICU+JSAKCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICAgIGdlbmUgJWluJSBicmFpbi5nZW5lcyB+ICdicmFpbicsCiAgICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QnLAogICAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gJ2RlZycsCiAgICAgICAgVCB+ICdvdGhlcicpCiAgICAgICkgJT4lIAogIGdncGxvdChhZXMoZnhuX2V4cCwgdXBwZXJRX2V4cCwgZ3JvdXAgPSBocGEpKSsKICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAyLjMsIHNsb3BlID0gLTIuNSkrCiAgIyBhbm5vdGF0ZShnZW9tID0gJ3RleHQnLCB4ID0gLjY1LCB5ID0gMCwgbGFiZWwgPSAneSA9IC0yLjV4ICsgMi41JywgaGp1c3QgPSAwKSsKICBnZW9tX3BvaW50KGRhdGEgPSB0aHJlc2gsIGFlcyh4ID0gZnhuLCB5ID0gZXhwKSwgc2l6ZSA9IDIsIGFscGhhID0gLjUpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScsIGFlcyhjb2xvciA9IGhwYSksIGx3ZCA9IC41LCBsdHkgPSAyKSsKICBsYWJzKHkgPSAnZXhwcmVzc2lvbicsIHggPSAnZnJhY3Rpb24gZXhwcmVzc2luZycKICAgICAgICMsIHN1YnRpdGxlID0gcGFzdGUwKCdwbG90dGluZyBxdWFudGlsZTogJywgdCkKICAgICAgICkrCiAgZmFjZXRfd3JhcCh+YnJvYWQsIHNjYWxlcyA9ICdmcmVlJykKCmBgYAoKCmBgYHtyfQp0ID0gLjkKCnRocmVzaCA9IHNlYWFkICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIG5vdC5icmFpbikgJT4lCiAgZ3JvdXBfYnkoYnJvYWQsIGNlbGxUeXBlKSAlPiUKICBzdW1tYXJpc2UoIAogICAgZXhwMSA9IHF1YW50aWxlKHVwcGVyUV9leHAsIHQpLAogICAgZnhuMSA9IHF1YW50aWxlKGZ4bl9leHAsIHQpCiAgKSAlPiUgCiAgbXV0YXRlKAogICAgZXhwID0gZXhwMSsuMTQyLAogICAgZnhuID0gZnhuMSsuMTQyLAogICAgaHBhID0gJ25ldy5kYXQnCiAgKSAKCnNlYWFkICU+JSAKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluJywKICAgICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gJ25vdCcsCiAgICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAnZGVnJywKICAgICAgICBUIH4gJ290aGVyJykKICAgICAgKSAlPiUgCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JQogICMgZmlsdGVyKAogICMgICBmeG5fZXhwID49IHRocmVzaCRmeG5bIHdoaWNoKHRocmVzaCRjZWxsVHlwZSA9PSBjZWxsVHlwZSkgXSAlPiUgdW5pcXVlKCksCiAgIyAgIHVwcGVyUV9leHAgPj0gdGhyZXNoJGV4cFsgd2hpY2godGhyZXNoJGNlbGxUeXBlID09IGNlbGxUeXBlKSBdICU+JSB1bmlxdWUoKSwKICAjICAgLnByZXNlcnZlID0gVAogICMgKSAlPiUKICAjIHVuZ3JvdXAoKSAlPiUKICAKICBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gLTIuNSAqIGZ4bl9leHAgKyAyLjMpICU+JQoKICBnZ3Bsb3QoYWVzKGZ4bl9leHAsIHVwcGVyUV9leHAsIGdyb3VwID0gaHBhKSkrCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMi4zLCBzbG9wZSA9IC0yLjUpKwogICMgYW5ub3RhdGUoZ2VvbSA9ICd0ZXh0JywgeCA9IC42NSwgeSA9IDAsIGxhYmVsID0gJ3kgPSAtMi41eCArIDIuNScsIGhqdXN0ID0gMCkrCiAgZ2VvbV9wb2ludChkYXRhID0gdGhyZXNoLCBhZXMoeCA9IGZ4biwgeSA9IGV4cCksIHNpemUgPSAyLCBhbHBoYSA9IC41KSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nLCBhZXMoY29sb3IgPSBocGEpLCBsd2QgPSAuNSwgbHR5ID0gMikrCiAgbGFicyh5ID0gJ2V4cHJlc3Npb24nLCB4ID0gJ2ZyYWN0aW9uIGV4cHJlc3NpbmcnCiAgICAgICAjLCBzdWJ0aXRsZSA9IHBhc3RlMCgncGxvdHRpbmcgcXVhbnRpbGU6ICcsIHQpCiAgICAgICApKwogIGZhY2V0X3dyYXAofmJyb2FkLCBzY2FsZXMgPSAnZnJlZScpCgpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnNlYWFkICU+JSAKICBnZ3Bsb3QoYWVzKHVwcGVyUV9leHAsIGZ4bl9leHApKSsgCiAgZ2VvbV9iaW4yZChhZXMoZmlsbCA9IC4uY291bnQuLiApKSsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXModHJhbnMgPSAnbG9nMTAnLCBvcHRpb24gPSAnQScpKwogIGdndGl0bGUoJ25vIGZpbHRlcicpKwogIGZhY2V0X3dyYXAofmJyb2FkKQpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnRocmVzaCA9IHNlYWFkICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIG5vdC5icmFpbikgJT4lCiAgZ3JvdXBfYnkoYnJvYWQsIGNlbGxUeXBlKSAlPiUKICBzdW1tYXJpc2UoIAogICAgZXhwMSA9IHF1YW50aWxlKHVwcGVyUV9leHAsIHQpLAogICAgZnhuMSA9IHF1YW50aWxlKGZ4bl9leHAsIHQpCiAgKSAlPiUgCiAgbXV0YXRlKAogICAgZXhwID0gZXhwMSsuMTQyLAogICAgZnhuID0gZnhuMSsuMTQyLAogICAgaHBhID0gJ25ldy5kYXQnCiAgKSAKCnNlYWFkICU+JSAKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluJywKICAgICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICdkZWcnLAogICAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90JywKICAgICAgICBUIH4gJ290aGVyJykKICAgICAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgICAgIAoKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUKICAjIGZpbHRlcigKICAjICAgZnhuX2V4cCA+PSB0aHJlc2gkZnhuWyB3aGljaCh0aHJlc2gkY2VsbFR5cGUgPT0gY2VsbFR5cGUpIF0gJT4lIHVuaXF1ZSgpLAogICMgICB1cHBlclFfZXhwID49IHRocmVzaCRleHBbIHdoaWNoKHRocmVzaCRjZWxsVHlwZSA9PSBjZWxsVHlwZSkgXSAlPiUgdW5pcXVlKCksCiAgIyAgIC5wcmVzZXJ2ZSA9IFQKICAjICkgJT4lCiAgIyB1bmdyb3VwKCkgJT4lCgogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMykgJT4lCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogICMgbXV0YXRlKCBleHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAuOSksIAogICMgICAgICAgICBmeG4gPSBxdWFudGlsZShmeG5fZXhwLCAuOSkKICAjICAgICAgICAgKSAlPiUgCiAgIyBncm91cF9ieShjZWxsVHlwZSkgJT4lCiAgIyBmaWx0ZXIoICApICU+JQogICMgdW5ncm91cCgpICU+JSAKICAKICBnZ3Bsb3QoYWVzKHVwcGVyUV9leHAsIGZ4bl9leHApKSsgCiAgZ2VvbV9iaW4yZChhZXMoZmlsbCA9IC4uY291bnQuLiApKSsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXModHJhbnMgPSAnbG9nMTAnLCBvcHRpb24gPSAnQScpKwogIGZhY2V0X3dyYXAofmJyb2FkKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD04fQoKc2VhYWQgJT4lIAogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluLmdlbmVzJywKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAndGFkLmRlZycsCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgVCB+ICdvdGhlcicpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCiAgZ3JvdXBfYnkoaHBhKSAlPiUgCiAgbXV0YXRlKAogICAgbiA9IGxlbmd0aCh1bmlxdWUoZ2VuZSkpLAogICAgaHBhMSA9IHBhc3RlMChocGEsICcsICcsIG4pCiAgICApICU+JSAKICBnZ3Bsb3QoYWVzKHVwcGVyUV9leHAsIGZ4bl9leHApKSsgCiAgZ2VvbV9iaW4yZChhZXMoZmlsbCA9IC4uY291bnQuLiApKSsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXModHJhbnMgPSAnbG9nMTAnLCBvcHRpb24gPSAnQScpKwogIGdndGl0bGUoJ25vIGZpbHRlcicpKwogIGZhY2V0X2dyaWQoYnJvYWR+aHBhMSkKIApgYGAKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD04fQoKdGhyZXNoID0gc2VhYWQgJT4lIAogIGZpbHRlcihnZW5lICVpbiUgbm90LmJyYWluKSAlPiUKICBncm91cF9ieShicm9hZCwgY2VsbFR5cGUpICU+JQogIHN1bW1hcmlzZSggCiAgICBleHAxID0gcXVhbnRpbGUodXBwZXJRX2V4cCwgdCksCiAgICBmeG4xID0gcXVhbnRpbGUoZnhuX2V4cCwgdCkKICApICU+JSAKICBtdXRhdGUoCiAgICBleHAgPSBleHAxKy4xNDIsCiAgICBmeG4gPSBmeG4xKy4xNDIsCiAgICBocGEgPSAnbmV3LmRhdCcKICApIAoKc2VhYWQgJT4lIAogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4nLAogICAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gJ3RhZC5kZWcnLAogICAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgICBUIH4gJ290aGVyJykKICAgICAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgICAgIAoKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUKICAjIGZpbHRlcigKICAjICAgZnhuX2V4cCA+PSB0aHJlc2gkZnhuWyB3aGljaCh0aHJlc2gkY2VsbFR5cGUgPT0gY2VsbFR5cGUpIF0gJT4lIHVuaXF1ZSgpLAogICMgICB1cHBlclFfZXhwID49IHRocmVzaCRleHBbIHdoaWNoKHRocmVzaCRjZWxsVHlwZSA9PSBjZWxsVHlwZSkgXSAlPiUgdW5pcXVlKCksCiAgIyAgIC5wcmVzZXJ2ZSA9IFQKICAjICkgJT4lCiAgIyB1bmdyb3VwKCkgJT4lCiAgCiAgZmlsdGVyKCB1cHBlclFfZXhwID49IC0yLjUgKiBmeG5fZXhwICsgMi4zKSAlPiUKICAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQoKICAjIGdyb3VwX2J5KGNlbGxUeXBlLCBocGEpICU+JQogICMgbXV0YXRlKHRvcF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjc1KSwKICAjICAgICAgICB0b3BfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgMC45NSkpICU+JQogICMgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JQogICMgZmlsdGVyKCB1cHBlclFfZXhwID4gdW5pcXVlKHRvcF9leHBbaHBhID09ICdub3QuYnJhaW4nXSkgLAogICMgICAgICAgICBmeG5fZXhwID4gdW5pcXVlKHRvcF9meG5baHBhID09ICdub3QuYnJhaW4nXSkgKSAlPiUKICAjIHVuZ3JvdXAoKSAlPiUKICAKICBncm91cF9ieShocGEpICU+JSAKICBtdXRhdGUoCiAgICBuID0gbGVuZ3RoKHVuaXF1ZShnZW5lKSksCiAgICBocGExID0gcGFzdGUwKGhwYSwgJywgJywgbikKICAgICkgJT4lIAogIGdncGxvdChhZXModXBwZXJRX2V4cCwgZnhuX2V4cCkpKyAKICBnZW9tX2JpbjJkKGFlcyhmaWxsID0gLi5jb3VudC4uICkpKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcyh0cmFucyA9ICdsb2cxMCcsIG9wdGlvbiA9ICdBJykrCiAgZ2d0aXRsZSgnZmlsdGVyZWQnKSsKICBmYWNldF9ncmlkKGJyb2FkfmhwYTEpCiAKYGBgCgoKIyMjIGZ4biBleHByZXNzZWQKYGBge3J9CiMgYWxzbyAiYnJhaW4gZ2VuZXMiOgojIHNjb3JlcyAlPiUgZmlsdGVyKGlzU2NvcmVkX29taWNzID09ICdZJywgT21pY3NTY29yZSA+IDApICU+JSBwdWxsKEdlbmVOYW1lKSAlPiUgdW5pcXVlKCkKCnNlYWFkICU+JSAKICAjIGZpbHRlcihpcy5uYShncm91cCkpICU+JSAKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgIGdlbmUgJWluJSBicmFpbi5nZW5lcyB+IHBhc3RlMCgnSFBBIGJyYWluIChuID0gJywgbGVuZ3RoKGludGVyc2VjdChnZW5lLCBicmFpbi5nZW5lcykpLCcgZ2VuZXMpJyksCiAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gcGFzdGUwKCdUQUQgREVHIChuID0gJywgbGVuZ3RoKGludGVyc2VjdChnZW5lLHRhZC5kZWcpKSwnIGdlbmVzKScpLAogICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gcGFzdGUwKCdIUEEgbm90IGJyYWluIChuID0gJywgbGVuZ3RoKGludGVyc2VjdChnZW5lLG5vdC5icmFpbikpLCcgZ2VuZXMpJyksCiAgICAgIFQgfiBwYXN0ZTAoJ290aGVyIChuID0gJywgbGVuZ3RoKHVuaXF1ZShzZXRkaWZmKGdlbmUsIHVuaW9uKHVuaW9uKGJyYWluLmdlbmVzLCB0YWQuZGVnKSwgbm90LmJyYWluKSkpKSAsJyBnZW5lcyknKQogICAgICApCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCiAgZ2dwbG90KGFlcyggZnhuX2V4cCwgZmlsbCA9IGhwYSkpKwogIGdlb21fZGVuc2l0eShhZXMoY29sb3IgPSBocGEpLCBhbHBoYSA9IC4xKSsKICAjIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gJ2RvZGdlJykrCiAgIyBzY2FsZV95X2xvZzEwKCkrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgnJykrc2NhbGVfY29sb3JfZGlzY3JldGUoJycpKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKG5yb3c9MikpKwogIGdnZm9yY2U6OmZhY2V0X3pvb20oeGxpbSA9IGMoMCwuMjUpLCB5bGltID0gYygwLDUpKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykKYGBgCgpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xM30KIyBzZWFhZCAlPiUgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSBzdW1tYXJpc2UobW4gPSBtZWRpYW4oZnJhY3Rpb25fZXhwcmVzc2VkKSkKCnNlYWFkICU+JSAKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgIGdlbmUgJWluJSBicmFpbi5nZW5lcyB+IHBhc3RlMCgnSFBBIGJyYWluIChuID0gJywgbGVuZ3RoKGludGVyc2VjdChnZW5lLCBicmFpbi5nZW5lcykpLCcgZ2VuZXMpJyksCiAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gcGFzdGUwKCdUQUQgREVHIChuID0gJywgbGVuZ3RoKGludGVyc2VjdChnZW5lLHRhZC5kZWcpKSwnIGdlbmVzKScpLAogICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gcGFzdGUwKCdIUEEgbm90IGJyYWluIChuID0gJywgbGVuZ3RoKGludGVyc2VjdChnZW5lLG5vdC5icmFpbikpLCcgZ2VuZXMpJyksCiAgICAgIFQgfiBwYXN0ZTAoJ290aGVyIChuID0gJywgbGVuZ3RoKHVuaXF1ZShzZXRkaWZmKGdlbmUsIHVuaW9uKHVuaW9uKGJyYWluLmdlbmVzLCB0YWQuZGVnKSwgbm90LmJyYWluKSkpKSAsJyBnZW5lcyknKQogICAgICApCiAgKSAlPiUgCiAgIyBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUgCiAgIyBtdXRhdGUodG9wX2V4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIDAuNzUpLAogICMgICAgICAgIHRvcF9meG4gPSBxdWFudGlsZShmeG5fZXhwLCAwLjc1KSkgJT4lIAogIGdncGxvdCguLCBhZXMoZnhuX2V4cCwgYnJvYWQsIGZpbGwgPSBocGEpKSArIAogIGdlb21fdmlvbGluKHNjYWxlID0gJ3dpZHRoJywgZHJhd19xdWFudGlsZXMgPSBjKC41KSkgKwogICMgZ2VvbV9wb2ludChhZXMoeCA9IHRvcF9meG4sIGNvbG9yID0gaHBhKSkrCiAgIyBzdGF0X3N1bW1hcnkoZnVuID0gZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCwwLjUpLCBnZW9tPSJwb2ludCIsIHNpemU9MiwgY29sb3I9InJlZCIsIHBvc2l0aW9uID0gJ2RvZGdlJykrCiAgIyBnZ2ZvcmNlOjpmYWNldF96b29tKHhsaW0gPSBjKDAsMC4wOCksIGhvcml6b250YWwgPSBGKQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDAuMjUpKQoKYGBgCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQgJT4lIAogICMgZmlsdGVyKGlzLm5hKGdyb3VwKSkgJT4lIAogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gcGFzdGUwKCdIUEEgYnJhaW4gKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsIGJyYWluLmdlbmVzKSksJyBnZW5lcyknKSwKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiBwYXN0ZTAoJ1RBRCBERUcgKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsdGFkLmRlZykpLCcgZ2VuZXMpJyksCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiBwYXN0ZTAoJ0hQQSBub3QgYnJhaW4gKG4gPSAnLCBsZW5ndGgoaW50ZXJzZWN0KGdlbmUsbm90LmJyYWluKSksJyBnZW5lcyknKSwKICAgICAgVCB+IHBhc3RlMCgnb3RoZXIgKG4gPSAnLCBsZW5ndGgodW5pcXVlKHNldGRpZmYoZ2VuZSwgdW5pb24odW5pb24oYnJhaW4uZ2VuZXMsIHRhZC5kZWcpLCBub3QuYnJhaW4pKSkpICwnIGdlbmVzKScpCiAgICAgICkKICApICU+JSAKICBmaWx0ZXIoIWlzLm5hKGhwYSkpICU+JSAKICBnZ3Bsb3QoYWVzKCBmeG5fZXhwLCBmaWxsID0gaHBhKSkrCiAgIyBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhKSwgYWxwaGEgPSAuMSkrCiAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCcnKStzY2FsZV9jb2xvcl9kaXNjcmV0ZSgnJykrCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLC4yNSksIHlsaW0gPSBjKDAsMWU1KSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcpCmBgYAoKYGBge3J9CiMgYWxzbyAiYnJhaW4gZ2VuZXMiOgojIHNjb3JlcyAlPiUgZmlsdGVyKGlzU2NvcmVkX29taWNzID09ICdZJywgT21pY3NTY29yZSA+IDApICU+JSBwdWxsKEdlbmVOYW1lKSAlPiUgdW5pcXVlKCkKCnNlYWFkICU+JSAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluLmdlbmVzJywKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAndGFkLmRlZycsCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgVCB+ICdvdGhlcicpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogICMgbXV0YXRlKHRvcF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjc1KSwKICAjICAgICAgICB0b3BfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgMC45NSkpICU+JSAKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUgIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID4gdW5pcXVlKHRvcF9leHBbaHBhID09ICdub3QuYnJhaW4nXSkgLAogICMgICAgICAgICBmeG5fZXhwID4gdW5pcXVlKHRvcF9meG5baHBhID09ICdub3QuYnJhaW4nXSkgKSAlPiUgCiAgIyB1bmdyb3VwKCkgJT4lIAogIAogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMykgJT4lCiAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gMiB8ICh1cHBlclFfZXhwID49IDEuMzMgJiBmeG5fZXhwID49IDAuMikgKSAlPiUKCiAgZ3JvdXBfYnkoaHBhKSAlPiUgCiAgbXV0YXRlKAogICAgbiA9IGxlbmd0aCh1bmlxdWUoZ2VuZSkpLAogICAgaHBhMSA9IHBhc3RlMChocGEsICcsICcsIG4pCiAgICApICU+JSAKICAKICBnZ3Bsb3QoYWVzKCBmeG5fZXhwLCBmaWxsID0gaHBhMSkpKwogICMgZ2VvbV9kZW5zaXR5KGFlcyhjb2xvciA9IGhwYTEpLCBhbHBoYSA9IC4xKSsKICBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoJycpK3NjYWxlX2NvbG9yX2Rpc2NyZXRlKCcnKSsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93PTIpKSsKICBnZ2ZvcmNlOjpmYWNldF96b29tKHhsaW0gPSBjKDAsLjI1KSwgeWxpbSA9IGMoMCwxZTUpKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykKYGBgCgoKCmBgYHtyfQojIGFsc28gImJyYWluIGdlbmVzIjoKIyBzY29yZXMgJT4lIGZpbHRlcihpc1Njb3JlZF9vbWljcyA9PSAnWScsIE9taWNzU2NvcmUgPiAwKSAlPiUgcHVsbChHZW5lTmFtZSkgJT4lIHVuaXF1ZSgpCgpzZWFhZCAlPiUgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gMiB8ICh1cHBlclFfZXhwID49IDEuMzMgJiBmeG5fZXhwID49IDAuMikgKSAlPiUKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgIGdlbmUgJWluJSBicmFpbi5nZW5lcyB+ICdicmFpbi5nZW5lcycsCiAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gJ3RhZC5kZWcnLAogICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gJ25vdC5icmFpbicsCiAgICAgIFQgfiAnb3RoZXInKQogICkgJT4lIAogIGZpbHRlcighaXMubmEoaHBhKSkgJT4lIAoKICAjIGdyb3VwX2J5KGNlbGxUeXBlLCBocGEpICU+JSAKICAjIG11dGF0ZSh0b3BfZXhwID0gcXVhbnRpbGUodXBwZXJRX2V4cCwgMC43NSksCiAgIyAgICAgICAgdG9wX2Z4biA9IHF1YW50aWxlKGZ4bl9leHAsIDAuOTUpKSAlPiUgCiAgIyBncm91cF9ieShjZWxsVHlwZSkgJT4lICAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+IHVuaXF1ZSh0b3BfZXhwW2hwYSA9PSAnbm90LmJyYWluJ10pICwKICAjICAgICAgICAgZnhuX2V4cCA+IHVuaXF1ZSh0b3BfZnhuW2hwYSA9PSAnbm90LmJyYWluJ10pICkgJT4lIAogICMgdW5ncm91cCgpICU+JSAKICAKICBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gLTIuNSAqIGZ4bl9leHAgKyAyLjMpICU+JQogIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCgogIGdyb3VwX2J5KGhwYSkgJT4lIAogIG11dGF0ZSgKICAgIG4gPSBsZW5ndGgodW5pcXVlKGdlbmUpKSwKICAgIGhwYTEgPSBwYXN0ZTAoaHBhLCAnLCAnLCBuKQogICAgKSAlPiUgCiAgCiAgZ2dwbG90KGFlcyggZnhuX2V4cCwgY29sb3IgPSBocGExKSkrCiAgZ2VvbV9kZW5zaXR5KCBhbHBoYSA9IC4xKSsKICAjIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gJ2RvZGdlJykrCiAgIyBzY2FsZV95X2xvZzEwKCkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4yLCBsdHkgPSAyKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCcnKStzY2FsZV9jb2xvcl9kaXNjcmV0ZSgnJykrCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLC4yNSksIHlsaW0gPSBjKDAsMS43KSkrIwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnKQpgYGAKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9MTN9CiMgc2VhYWQgJT4lIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUgc3VtbWFyaXNlKG1uID0gbWVkaWFuKGZyYWN0aW9uX2V4cHJlc3NlZCkpCgpzZWFhZCAlPiUgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gMiB8ICh1cHBlclFfZXhwID49IDEuMzMgJiBmeG5fZXhwID49IDAuMikgKSAlPiUKICBtdXRhdGUoCiAgICBocGEgPSBjYXNlX3doZW4oCiAgICAgIGdlbmUgJWluJSBicmFpbi5nZW5lcyB+ICdicmFpbi5nZW5lcycsCiAgICAgIGdlbmUgJWluJSB0YWQuZGVnIH4gJ3RhZC5kZWcnLAogICAgICBnZW5lICVpbiUgbm90LmJyYWluIH4gJ25vdC5icmFpbicsCiAgICAgIFQgfiAnb3RoZXInKQogICkgJT4lIAogIGZpbHRlcighaXMubmEoaHBhKSkgJT4lIAoKICAjIGdyb3VwX2J5KGNlbGxUeXBlLCBocGEpICU+JSAKICAjIG11dGF0ZSh0b3BfZXhwID0gcXVhbnRpbGUodXBwZXJRX2V4cCwgMC43NSksCiAgIyAgICAgICAgdG9wX2Z4biA9IHF1YW50aWxlKGZ4bl9leHAsIDAuOTUpKSAlPiUgCiAgIyBncm91cF9ieShjZWxsVHlwZSkgJT4lICAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+IHVuaXF1ZSh0b3BfZXhwW2hwYSA9PSAnbm90LmJyYWluJ10pICwKICAjICAgICAgICAgZnhuX2V4cCA+IHVuaXF1ZSh0b3BfZnhuW2hwYSA9PSAnbm90LmJyYWluJ10pICkgJT4lIAogICMgdW5ncm91cCgpICU+JSAKCiAgZmlsdGVyKCB1cHBlclFfZXhwID49IC0yLjUgKiBmeG5fZXhwICsgMi4zKSAlPiUKICAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQoKICBncm91cF9ieShocGEpICU+JSAKICBtdXRhdGUoCiAgICBuID0gbGVuZ3RoKHVuaXF1ZShnZW5lKSksCiAgICBocGExID0gcGFzdGUwKGhwYSwgJywgJywgbikKICAgICkgJT4lIAoKICBnZ3Bsb3QoLiwgYWVzKGZ4bl9leHAsIGJyb2FkLCBmaWxsID0gaHBhMSkpICsgCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAnd2lkdGgnLCBkcmF3X3F1YW50aWxlcyA9IGMoLjUpLCB0cmltID0gRikgKwogICMgZ2VvbV9wb2ludChhZXMoeCA9IHRvcF9meG4sIGNvbG9yID0gaHBhKSkrCiAgIyBzdGF0X3N1bW1hcnkoZnVuID0gZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCwwLjUpLCBnZW9tPSJwb2ludCIsIHNpemU9MiwgY29sb3I9InJlZCIsIHBvc2l0aW9uID0gJ2RvZGdlJykrCiAgIyBnZ2ZvcmNlOjpmYWNldF96b29tKHhsaW0gPSBjKDAsMC4wOCksIGhvcml6b250YWwgPSBGKQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDEpKQoKYGBgCgoKIyMjIGF2ZyBleHByZXNzaW9uCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQgJT4lIAogICMgZmlsdGVyKGlzLm5hKGdyb3VwKSkgJT4lIAogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluLmdlbmVzJywKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAndGFkLmRlZycsCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgVCB+ICdvdGhlcicpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCiAgZ3JvdXBfYnkoaHBhKSAlPiUgCiAgbXV0YXRlKAogICAgbiA9IGxlbmd0aCh1bmlxdWUoZ2VuZSkpLAogICAgaHBhMSA9IHBhc3RlMChocGEsICcsICcsIG4pCiAgICApICU+JSAKICBnZ3Bsb3QoYWVzKCAodXBwZXJRX2V4cCksIGZpbGwgPSBocGExKSkrCiAgZ2VvbV9kZW5zaXR5KGFlcyhjb2xvciA9IGhwYSksIGFscGhhID0gLjEpKwogICMgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCcnKStzY2FsZV9jb2xvcl9kaXNjcmV0ZSgnJykrCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDIpLCB5bGltID0gYygwLDEuMykgKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykKCmBgYAoKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9MTMsIHdhcm5pbmc9RkFMU0V9CiMgc2VhYWQgJT4lIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUgc3VtbWFyaXNlKG1uID0gbWVkaWFuKGZyYWN0aW9uX2V4cHJlc3NlZCkpCgpzZWFhZCAlPiUgCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4uZ2VuZXMnLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICd0YWQuZGVnJywKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QuYnJhaW4nLAogICAgICBUIH4gJ290aGVyJykKICApICU+JSAKICBmaWx0ZXIoIWlzLm5hKGhwYSkpICU+JSAKICBncm91cF9ieShocGEpICU+JSAKICBtdXRhdGUoCiAgICBuID0gbGVuZ3RoKHVuaXF1ZShnZW5lKSksCiAgICBocGExID0gcGFzdGUwKGhwYSwgJywgJywgbikKICAgICkgJT4lIAogICMgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogICMgbXV0YXRlKHRvcF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjc1KSwKICAjICAgICAgICB0b3BfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgMC43NSkpICU+JSAKICBnZ3Bsb3QoLiwgYWVzKHVwcGVyUV9leHAsIGJyb2FkLCBmaWxsID0gaHBhMSkpICsgCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAnd2lkdGgnLCBkcmF3X3F1YW50aWxlcyA9IGMoLjUpKSArCiAgIyBnZW9tX3BvaW50KGFlcyh4ID0gdG9wX2V4cCwgY29sb3IgPSBocGEpKSsKICAjIHN0YXRfc3VtbWFyeShmdW4gPSBmdW5jdGlvbih4KSBxdWFudGlsZSh4LDAuNSksIGdlb209InBvaW50Iiwgc2l6ZT0yLCBjb2xvcj0icmVkIiwgcG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIGdnZm9yY2U6OmZhY2V0X3pvb20oeGxpbSA9IGMoMCwwLjA4KSwgaG9yaXpvbnRhbCA9IEYpCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsNikpCgpgYGAKCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQgJT4lIAogICMgZmlsdGVyKGlzLm5hKGdyb3VwKSkgJT4lIAogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluLmdlbmVzJywKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAndGFkLmRlZycsCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgVCB+ICdvdGhlcicpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCiAgZ3JvdXBfYnkoaHBhKSAlPiUgCiAgbXV0YXRlKAogICAgbiA9IGxlbmd0aCh1bmlxdWUoZ2VuZSkpLAogICAgaHBhMSA9IHBhc3RlMChocGEsICcsICcsIG4pCiAgICApICU+JSAKICBnZ3Bsb3QoYWVzKCAodXBwZXJRX2V4cCksIGZpbGwgPSBocGExKSkrCiAgIyBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhKSwgYWxwaGEgPSAuMSkrCiAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCcnKStzY2FsZV9jb2xvcl9kaXNjcmV0ZSgnJykrCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDIpLCB5bGltID0gYygwLDMuNWU0KSApKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnKQoKYGBgCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQgJT4lIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4uZ2VuZXMnLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICd0YWQuZGVnJywKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QuYnJhaW4nLAogICAgICBUIH4gJ290aGVyJykKICApICU+JSAKICBmaWx0ZXIoIWlzLm5hKGhwYSkpICU+JSAKCiAgIyBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUgCiAgIyBtdXRhdGUodG9wX2V4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIDAuNzUpLAogICMgICAgICAgIHRvcF9meG4gPSBxdWFudGlsZShmeG5fZXhwLCAwLjk1KSkgJT4lIAogICMgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPiB1bmlxdWUodG9wX2V4cFtocGEgPT0gJ25vdC5icmFpbiddKSAsCiAgIyAgICAgICAgIGZ4bl9leHAgPiB1bmlxdWUodG9wX2Z4bltocGEgPT0gJ25vdC5icmFpbiddKSApICU+JSAKICAjIHVuZ3JvdXAoKSAlPiUgCiAgCiAgZmlsdGVyKCB1cHBlclFfZXhwID49IC0yLjUgKiBmeG5fZXhwICsgMi4zKSAlPiUKICAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQoKICBncm91cF9ieShocGEpICU+JSAKICBtdXRhdGUoCiAgICBuID0gbGVuZ3RoKHVuaXF1ZShnZW5lKSksCiAgICBocGExID0gcGFzdGUwKGhwYSwgJywgJywgbikKICAgICkgJT4lIAogIAogIGdncGxvdChhZXMoIHVwcGVyUV9leHAsIGZpbGwgPSBocGExKSkrCiAgIyBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gaHBhKSwgYWxwaGEgPSAuMSkrCiAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAnZG9kZ2UnKSsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCcnKStzY2FsZV9jb2xvcl9kaXNjcmV0ZSgnJykrCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDIpLCB5bGltID0gYygwLDMuNWU0KSApKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnKQpgYGAKCgpgYGB7cn0KIyBhbHNvICJicmFpbiBnZW5lcyI6CiMgc2NvcmVzICU+JSBmaWx0ZXIoaXNTY29yZWRfb21pY3MgPT0gJ1knLCBPbWljc1Njb3JlID4gMCkgJT4lIHB1bGwoR2VuZU5hbWUpICU+JSB1bmlxdWUoKQoKc2VhYWQgJT4lIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCiAgbXV0YXRlKAogICAgaHBhID0gY2FzZV93aGVuKAogICAgICBnZW5lICVpbiUgYnJhaW4uZ2VuZXMgfiAnYnJhaW4uZ2VuZXMnLAogICAgICBnZW5lICVpbiUgdGFkLmRlZyB+ICd0YWQuZGVnJywKICAgICAgZ2VuZSAlaW4lIG5vdC5icmFpbiB+ICdub3QuYnJhaW4nLAogICAgICBUIH4gJ290aGVyJykKICApICU+JSAKICBmaWx0ZXIoIWlzLm5hKGhwYSkpICU+JSAKCiAgIyBncm91cF9ieShjZWxsVHlwZSwgaHBhKSAlPiUgCiAgIyBtdXRhdGUodG9wX2V4cCA9IHF1YW50aWxlKHVwcGVyUV9leHAsIDAuNzUpLAogICMgICAgICAgIHRvcF9meG4gPSBxdWFudGlsZShmeG5fZXhwLCAwLjk1KSkgJT4lIAogICMgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPiB1bmlxdWUodG9wX2V4cFtocGEgPT0gJ25vdC5icmFpbiddKSAsCiAgIyAgICAgICAgIGZ4bl9leHAgPiB1bmlxdWUodG9wX2Z4bltocGEgPT0gJ25vdC5icmFpbiddKSApICU+JSAKICAjIHVuZ3JvdXAoKSAlPiUgCgogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMykgJT4lCiAgCiAgIyBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gMiB8ICh1cHBlclFfZXhwID49IDEuMzMgJiBmeG5fZXhwID49IDAuMikgKSAlPiUKCiAgZ3JvdXBfYnkoaHBhKSAlPiUgCiAgbXV0YXRlKAogICAgbiA9IGxlbmd0aCh1bmlxdWUoZ2VuZSkpLAogICAgaHBhMSA9IHBhc3RlMChocGEsICcsICcsIG4pCiAgICApICU+JSAKCiAgZ2dwbG90KGFlcyggdXBwZXJRX2V4cCwgY29sb3IgPSBocGExICkpKwogIGdlb21fZGVuc2l0eSggYWxwaGEgPSAuMSkrCiAgIyBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoJycpK3NjYWxlX2NvbG9yX2Rpc2NyZXRlKCcnKSsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdz0yKSkrCiAgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDIpLCB5bGltID0gYygwLDEuMykgKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykKYGBgCgpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xMywgd2FybmluZz1GQUxTRX0KIyBzZWFhZCAlPiUgZ3JvdXBfYnkoY2VsbFR5cGUpICU+JSBzdW1tYXJpc2UobW4gPSBtZWRpYW4oZnJhY3Rpb25fZXhwcmVzc2VkKSkKCnNlYWFkICU+JSAKICAjIGZpbHRlciggdXBwZXJRX2V4cCA+PSAyIHwgKHVwcGVyUV9leHAgPj0gMS4zMyAmIGZ4bl9leHAgPj0gMC4yKSApICU+JQogIG11dGF0ZSgKICAgIGhwYSA9IGNhc2Vfd2hlbigKICAgICAgZ2VuZSAlaW4lIGJyYWluLmdlbmVzIH4gJ2JyYWluLmdlbmVzJywKICAgICAgZ2VuZSAlaW4lIHRhZC5kZWcgfiAndGFkLmRlZycsCiAgICAgIGdlbmUgJWluJSBub3QuYnJhaW4gfiAnbm90LmJyYWluJywKICAgICAgVCB+ICdvdGhlcicpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShocGEpKSAlPiUgCgogICMgZ3JvdXBfYnkoY2VsbFR5cGUsIGhwYSkgJT4lIAogICMgbXV0YXRlKHRvcF9leHAgPSBxdWFudGlsZSh1cHBlclFfZXhwLCAwLjc1KSwKICAjICAgICAgICB0b3BfZnhuID0gcXVhbnRpbGUoZnhuX2V4cCwgMC45NSkpICU+JSAKICAjIGdyb3VwX2J5KGNlbGxUeXBlKSAlPiUgIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID4gdW5pcXVlKHRvcF9leHBbaHBhID09ICdub3QuYnJhaW4nXSkgLAogICMgICAgICAgICBmeG5fZXhwID4gdW5pcXVlKHRvcF9meG5baHBhID09ICdub3QuYnJhaW4nXSkgKSAlPiUgCiAgIyB1bmdyb3VwKCkgJT4lIAoKICBmaWx0ZXIoIHVwcGVyUV9leHAgPj0gLTIuNSAqIGZ4bl9leHAgKyAyLjMpICU+JQogIAogICMgZmlsdGVyKCB1cHBlclFfZXhwID49IDIgfCAodXBwZXJRX2V4cCA+PSAxLjMzICYgZnhuX2V4cCA+PSAwLjIpICkgJT4lCgogIGdyb3VwX2J5KGhwYSkgJT4lIAogIG11dGF0ZSgKICAgIG4gPSBsZW5ndGgodW5pcXVlKGdlbmUpKSwKICAgIGhwYTEgPSBwYXN0ZTAoaHBhLCAnLCAnLCBuKQogICAgKSAlPiUgCiAgCiAgZ2dwbG90KC4sIGFlcyh1cHBlclFfZXhwLCBicm9hZCwgZmlsbCA9IGhwYTEpKSArIAogIGdlb21fdmlvbGluKHNjYWxlID0gJ3dpZHRoJywgZHJhd19xdWFudGlsZXMgPSBjKC41KSwgdHJpbSA9IEYpICsKICAjIGdlb21fcG9pbnQoYWVzKHggPSB0b3BfZXhwLCBjb2xvciA9IGhwYSkpKwogICMgc3RhdF9zdW1tYXJ5KGZ1biA9IGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsMC41KSwgZ2VvbT0icG9pbnQiLCBzaXplPTIsIGNvbG9yPSJyZWQiLCBwb3NpdGlvbiA9ICdkb2RnZScpKwogICMgZ2dmb3JjZTo6ZmFjZXRfem9vbSh4bGltID0gYygwLDAuMDgpLCBob3Jpem9udGFsID0gRikKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCw2KSkKCmBgYAoKYGBge3J9CnNlYWFkLmV4cHIgPC0gc2VhYWQgJT4lIAogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMyApICU+JQogIHB1bGwoZ2VuZSkgJT4lIAogIHVuaXF1ZSgpCmBgYAoKCiMgTk9ERTogb3ZlcmFsbAoKYGBge3J9CnRvdC5ub2RlcyA9IHYuYXR0ciRuYW1lCmZpbHQubm9kZXMgPSB1bmlvbihzZWFhZC5leHByLCB0YWQuZGVnKSAlPiUgdW5pb24oLiwgYnJhaW4uZ2VuZXMpICU+JSBpbnRlcnNlY3QoLix2LmF0dHIkbmFtZSkgCgpncmlkOjpncmlkLm5ld3BhZ2UoKQpncmlkOjpncmlkLmRyYXcoCiAgVmVubkRpYWdyYW06OnZlbm4uZGlhZ3JhbSgKICAgICAgICB4ID0gbGlzdCgKICAgICAgICAgIGBQYXRoQ29tbW9uc19OV1xuKDE5MDg3KWAgPSB2LmF0dHIkbmFtZSAlPiUgLlshaXMubmEoLildLCAKICAgICAgICAgIGBIdW1hblByb3RBdGxhc19icmFpblxuKDQxNDApYCA9IGJyYWluLmdlbmVzICU+JSAuWyFpcy5uYSguKV0sCiAgICAgICAgICBgU2VhQURcbigxMDU5NClgID0gc2VhYWQuZXhwciAlPiUgLlshaXMubmEoLildLAogICAgICAgICAgYFRyZWF0QURfREVHXG4oMTE5MTApYCA9IHRhZC5kZWcgJT4lIC5bIWlzLm5hKC4pXQogICAgICAgICksCiAgICAgICAgZmlsZW5hbWUgPSBOVUxMLAogICAgICAgIGZvcmNlLnVuaXF1ZSA9IFQsCiAgICAgICAgbHR5ID0gMCwgYWxwaGEgPSAuMyAsIAogICAgICAgIGZpbGwgPSBjKCdsaWdodCBibHVlJywneWVsbG93JywgJ2dyZWVuJywncHVycGxlJyksCiAgICAgICAgCiAgICAgICAgc3ViID0gcGFzdGUwKCcjIFBhdGh3YXkgQ29tbW9ucyBub2RlczogJywgbGVuZ3RoKHRvdC5ub2RlcyksCiAgICAgICAgICAgICAgICAgICAgICdcbiMgZmlsdGVyZWQgbm9kZXM6ICcsIGxlbmd0aChmaWx0Lm5vZGVzKSwgCiAgICAgICAgICAgICAgICAgICAgICcgKCcsIHNpZ25pZiggMTAwKmxlbmd0aChmaWx0Lm5vZGVzKS9sZW5ndGgodG90Lm5vZGVzKSwgZGlnaXRzID0gNCksICclKScgKSwKICAgICAgICAKICAgICAgICBjYXQuY2V4ID0gLjgsCiAgICAgICAgZXh0LnBvcyA9IDE4MCwKICAgICAgICBleHQuZGlzdCA9IC0uMQogICAgICAgICkKKQoKYGBgCgoKIyBFREdFOiBQYXRod2F5IENvbW1vbnMgTmV0d29yawoKU3BlY2lmeSB0aGUgZGlyZWN0ZWQtZWRnZSB0eXBlcyB0byBmaWx0ZXIgdGhlIFBhdGh3YXkgQ29tbW9ucyBncmFwaCAgCmBgYHtyfQpkaXJlY3RlZF9lZGdlX3R5cGVzID0gYygiY2F0YWx5c2lzLXByZWNlZGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgImNvbnRyb2xzLWV4cHJlc3Npb24tb2YiLAogICAgICAgICAgICAgICAgICAgICAgICAiY29udHJvbHMtcGhvc3Bob3J5bGF0aW9uLW9mIiwKICAgICAgICAgICAgICAgICAgICAgICAgImNvbnRyb2xzLXN0YXRlLWNoYW5nZS1vZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICJjb250cm9scy10cmFuc3BvcnQtb2YiCiAgICAgICAgICAgICAgICAgICAgICAgICkKCiMgZGlyLm5ldCA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZCA9IG5ldC50YmwgJT4lIGZpbHRlcihpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpLCBkaXJlY3RlZCA9IFQpCmBgYAoKSG93IG1hbnkgZWRnZXMgZnJvbSBlYWNoIHNvdXJjZT8gIApgYGB7ciB3YXJuaW5nPUZBTFNFfQpiaW5kX2NvbHMoCiAgICBzb3VyY2VzID0gc3RyX3NwbGl0KG5ldC50Ymwkc291cmNlcywnLCcpICU+JSB1bmxpc3QgJT4lIHVuaXF1ZSwgCiAgICBuX2VkZ2UgPSBtYXBfZGJsKCAKICAgICAgICBzdHJfc3BsaXQobmV0LnRibCRzb3VyY2VzLCcsJykgJT4lIHVubGlzdCAlPiUgdW5pcXVlLCAKICAgICAgICB+IG5ldC50YmwgJT4lIGZpbHRlcihncmVwbCgueCwgc291cmNlcykpICU+JSBucm93KCkgKSwKICAgIGFueV9kaXJlY3RlZCA9IG1hcF9sZ2woCiAgICAgICAgc3RyX3NwbGl0KG5ldC50Ymwkc291cmNlcywnLCcpICU+JSB1bmxpc3QgJT4lIHVuaXF1ZSwgCiAgICAgICAgfiBuZXQudGJsICU+JSAKICAgICAgICAgICAgbXV0YXRlKGRpcmVjdGVkID0gaWZfZWxzZShpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMsICdkaXInLCd1bmRpcicpICkgJT4lIAogICAgICAgICAgICBmaWx0ZXIoZ3JlcGwoLngsIHNvdXJjZXMpKSAlPiUgcHVsbChkaXJlY3RlZCkgJT4lIGFueSguID09ICdkaXInKQogICAgKQopICU+JSAKICBtdXRhdGUoYW55X2RpcmVjdGVkID0gaWZfZWxzZShpcy5uYShhbnlfZGlyZWN0ZWQpLCBGQUxTRSwgVFJVRSksCiAgICAgICAgIGFueV9kaXJlY3RlZCA9IGZhY3RvcihhbnlfZGlyZWN0ZWQsIGxldmVscz1jKCdUUlVFJywnRkFMU0UnKSkpICU+JQogIGFycmFuZ2UoZGVzYyhuX2VkZ2UpKSAlPiUgbXV0YXRlKHNvdXJjZXMgPSBmY3RfcmVsZXZlbChzb3VyY2VzLCBzb3VyY2VzKSkgJT4lCiAgZ2dwbG90KGFlcyhzb3VyY2VzLCBuX2VkZ2UpKSArIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCBhZXMoZmlsbCA9IGFueV9kaXJlY3RlZCkpICsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkKICAgICAgICAsIGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnKQpgYGAKCldoaWNoIGVkZ2Ugc291cmNlcyBhcmUgKGdlbmVyYWxseSkgd2VsbCBzdXBwb3J0ZWQ/ICAKYGBge3Igd2FybmluZz1GQUxTRX0KYmluZF9jb2xzKAogICAgc291cmNlcyA9IHN0cl9zcGxpdChuZXQudGJsJHNvdXJjZXMsJywnKSAlPiUgdW5saXN0ICU+JSB1bmlxdWUsIAogICAgbl9lZGdlID0gbWFwX2RibCggCiAgICAgIHN0cl9zcGxpdChuZXQudGJsJHNvdXJjZXMsJywnKSAlPiUgdW5saXN0ICU+JSB1bmlxdWUsIAogICAgICB+IG5ldC50YmwgJT4lIGZpbHRlcihncmVwbCgueCwgc291cmNlcykpICU+JSBucm93KCkgKQogICAgLCBtZWRpYW5fZXZpZGVuY2VfcGVyX2VkZ2UgPSBtYXBfZGJsKCAKICAgICAgc3RyX3NwbGl0KG5ldC50Ymwkc291cmNlcywnLCcpICU+JSB1bmxpc3QgJT4lIHVuaXF1ZSwgCiAgICAgIH4gbmV0LnRibCAlPiUgZmlsdGVyKGdyZXBsKC54LCBzb3VyY2VzKSkgJT4lIHB1bGwobl9lZGdlX2V2aWRlbmNlKSAlPiUgbWVkaWFuKCkgKQogICAgLCBhbnlfZGlyZWN0ZWQgPSBtYXBfbGdsKAogICAgICAgIHN0cl9zcGxpdChuZXQudGJsJHNvdXJjZXMsJywnKSAlPiUgdW5saXN0ICU+JSB1bmlxdWUsIAogICAgICAgIH4gbmV0LnRibCAlPiUgCiAgICAgICAgICAgIG11dGF0ZShkaXJlY3RlZCA9IGlmX2Vsc2UoaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzLCAnZGlyJywndW5kaXInKSApICU+JSAKICAgICAgICAgICAgZmlsdGVyKGdyZXBsKC54LCBzb3VyY2VzKSkgJT4lIHB1bGwoZGlyZWN0ZWQpICU+JSBhbnkoLiA9PSAnZGlyJykgKQopICU+JSAKICBtdXRhdGUoYW55X2RpcmVjdGVkID0gaWZfZWxzZShpcy5uYShhbnlfZGlyZWN0ZWQpLCBGQUxTRSwgVFJVRSksCiAgICAgICAgIGFueV9kaXJlY3RlZCA9IGZhY3RvcihhbnlfZGlyZWN0ZWQsIGxldmVscz1jKCdUUlVFJywnRkFMU0UnKSkpICU+JQogIGFycmFuZ2UoZGVzYyhuX2VkZ2UpKSAlPiUgbXV0YXRlKHNvdXJjZXMgPSBmY3RfcmVsZXZlbChzb3VyY2VzLCBzb3VyY2VzKSkgJT4lIAogIGdncGxvdChhZXMobl9lZGdlLCBtZWRpYW5fZXZpZGVuY2VfcGVyX2VkZ2UpKSArCiAgZ2VvbV9wb2ludCggYWVzKGNvbG9yID0gYW55X2RpcmVjdGVkICkpICsgCiAgc2NhbGVfeF9sb2cxMCgpKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykrCiAgZ2dyZXBlbDo6Z2VvbV9sYWJlbF9yZXBlbChhZXMobGFiZWwgPSBzb3VyY2VzKSwgc2l6ZSA9IDMpCiAgIyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkpIApgYGAKCkRpc3RyaWJ1dGlvbiBvZiBldmlkZW5jZSBzdXBwb3J0IGZvciBlZGdlcwpgYGB7cn0KbmV0LnRibCAlPiUgCiAgbXV0YXRlKGRpcmVjdGVkID0gaWZfZWxzZShpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMsICdkaXInLCd1bmRpcicpICkgJT4lIAogIGdncGxvdChhZXMobl9lZGdlX2V2aWRlbmNlKSkrCiAgc3RhdF9lY2RmKGdlb20gPSAnbGluZScsIGFlcyhjb2xvciA9IGRpcmVjdGVkKSkrCiAgIyBnZW9tX2RlbnNpdHkoYWVzKGZpbGwgPSBkaXJlY3RlZCkpKwogICMgZ2VvbV9oaXN0b2dyYW0oYWVzKGZpbGwgPSBkaXJlY3RlZCksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkrCiAgIyBzY2FsZV95X2xvZzEwKCkrCiAgc2NhbGVfeF9sb2cxMCgpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIsIGx0eSA9IDIsIGx3ZCA9IC41KSsKICBsYWJzKHkgPSAnZnJhY3Rpb24gb2YgZWRnZXMnKQpgYGAKRGlzdHJpYnV0aW9uIG9mIGV2aWRlbmNlIHN1cHBvcnQgZm9yIGVkZ2VzCmBgYHtyfQpuZXQudGJsICU+JSAKICBtdXRhdGUoZGlyZWN0ZWQgPSBpZl9lbHNlKGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcywgJ2RpcicsJ3VuZGlyJykgKSAlPiUgCiAgZ2dwbG90KGFlcyhuX2VkZ2VfdHlwZXMpKSsKICBzdGF0X2VjZGYoZ2VvbSA9ICdsaW5lJywgYWVzKGNvbG9yID0gZGlyZWN0ZWQpKSsKICAjIGdlb21fZGVuc2l0eShhZXMoZmlsbCA9IGRpcmVjdGVkKSkrCiAgIyBnZW9tX2hpc3RvZ3JhbShhZXMoZmlsbCA9IGRpcmVjdGVkKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSsKICAjIHNjYWxlX3lfbG9nMTAoKSsKICAjIHNjYWxlX3hfbG9nMTAoKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyLCBsdHkgPSAyLCBsd2QgPSAuNSkrCiAgbGFicyh5ID0gJ2ZyYWN0aW9uIG9mIGVkZ2VzJykKYGBgCgpEaXN0cmlidXRpb24gb2YgZXZpZGVuY2Ugc3VwcG9ydCBmb3IgZWRnZXMKYGBge3J9Cm5ldC50YmwgJT4lIAogIG11dGF0ZShkaXJlY3RlZCA9IGlmX2Vsc2UoaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzLCAnZGlyJywndW5kaXInKSApICU+JSAKICBnZ3Bsb3QoYWVzKG5fc291cmNlKSkrCiAgc3RhdF9lY2RmKGdlb20gPSAnbGluZScsIGFlcyhjb2xvciA9IGRpcmVjdGVkKSkrCiAgIyBnZW9tX2RlbnNpdHkoYWVzKGZpbGwgPSBkaXJlY3RlZCkpKwogICMgZ2VvbV9oaXN0b2dyYW0oYWVzKGZpbGwgPSBkaXJlY3RlZCksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkrCiAgIyBzY2FsZV95X2xvZzEwKCkrCiAgc2NhbGVfeF9sb2cxMCgpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIsIGx0eSA9IDIsIGx3ZCA9IC41KSsKICBsYWJzKHkgPSAnZnJhY3Rpb24gb2YgZWRnZXMnKQpgYGAKCkRpc3RyaWJ1dGlvbiBvZiBldmlkZW5jZSBzdXBwb3J0IGZvciBlZGdlcwpgYGB7cn0KbmV0LnRibCAlPiUgCiAgbXV0YXRlKGRpcmVjdGVkID0gaWZfZWxzZShpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMsICdkaXInLCd1bmRpcicpICkgJT4lCiAgZmlsdGVyKG5fZWRnZV9ldmlkZW5jZSA+IDEKICAgICAgICAgfCAobl9lZGdlX2V2aWRlbmNlID09IDEgJiBuX2VkZ2VfdHlwZXMgPiAyICYgbl9zb3VyY2UgPiAyKSkgJT4lIAogIGdncGxvdChhZXMobl9lZGdlKSkrCiAgIyBzdGF0X2VjZGYoZ2VvbSA9ICdsaW5lJywgYWVzKGNvbG9yID0gZGlyZWN0ZWQpKSsKICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICdncmV5MjAnLCBmaWxsID0gJ2dyZXk4MCcpKwogIAogICMgc2NhbGVfeF9sb2cxMCgpKwogICMgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMiwgbHR5ID0gMiwgbHdkID0gLjUpKwogIGxhYnMoKQpgYGAKCkRpc3RyaWJ1dGlvbiBvZiBldmlkZW5jZSBzdXBwb3J0IGZvciBlZGdlcwpgYGB7cn0KbmV0LnRibCAlPiUgCiAgIyBtdXRhdGUoZGlyZWN0ZWQgPSBpZl9lbHNlKGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcywgJ2RpcicsJ3VuZGlyJykgKSAlPiUgCiAgZ2dwbG90KGFlcyggbl9lZGdlX3R5cGVzLCBuX2VkZ2VfZXZpZGVuY2UgKSkrCiAgZ2VvbV9wb2ludCgpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpKwogIHNjYWxlX3lfbG9nMTAoKSsKICAjIHNjYWxlX3hfbG9nMTAoKSsKICAjIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIsIGx0eSA9IDIsIGx3ZCA9IC41KSsKICBsYWJzKCkKYGBgCgojIEVER0U6IFBhaXJ3aXNlIHBhcnRpYWwgY29ycmVsYXRpb25zCgpEcm9wcGluZyB0aGlzIGZvciB0aGUgbW9tZW50IGJlY2F1c2U6CjEuIHRoZSBjdXJyZW50IHBjb3IgY2FsY3VsYXRpb25zIHdvdWxkIG5lZWQgdG8gYmUgcmVjYWxjdWxhdGVkIG9uIGEgdGlzc3VlIHNwZWNpZmljIGJhc2lzCjIuIHRoZSBkYXRhIGFyZSBsYXJnZSwgdW53aWVsZHksIGFuZCBvZiB1bmNlcnRhaW4gdXRpbGl0eSAKCk1heSByZXR1cm4gYXQgYSBsYXRlciB0aW1lLiAKCjwhLS0gIyMgUk9TTUFQIC0tPgo8IS0tIExvYWQgUk9TTUFQIHBhaXJ3aXNlIHBhcnRpYWwgY29ycmVsYXRpb25zIC0tPgo8IS0tIGBgYHtyfSAtLT4KPCEtLSAjIHN0ID0gU3lzLnRpbWUoKSAtLT4KPCEtLSAjICAtLT4KPCEtLSAjICMgZG93bmxvYWQgYW5kIHBpdm90IHBjb3IgdGFibGUgLS0+CjwhLS0gIyBzeW5Mb2dpbigpIC0tPgo8IS0tICMgcm0ucGNvciA8LSByZWFkX2NzdihzeW5HZXQoJ3N5bjUxMDYxNzkwJykkcGF0aCkgJT4lICAtLT4KPCEtLSAjICAgcmVuYW1lKGdlbmUxID0gWDEpICU+JSAgLS0+CjwhLS0gIyAgIHBpdm90X2xvbmdlcihjb2xzID0gLWdlbmUxLCBuYW1lc190byA9ICdnZW5lMicsIHZhbHVlc190byA9ICdwY29yJykgJT4lICAtLT4KPCEtLSAjICAgZmlsdGVyKCBnZW5lMSAhPSBnZW5lMiApICAtLT4KPCEtLSAjICAtLT4KPCEtLSAjIGNhdCgnZG93bmxvYWQ6IFxuJykgLS0+CjwhLS0gIyBTeXMudGltZSgpIC0gc3QgLS0+CjwhLS0gIyAgLS0+CjwhLS0gIyAjIGdldCBnZW5lIHN5bWJvbHMgY29ycmVzcG9uZGluZyB0byBFbnNlbWJsIElEcyAtLT4KPCEtLSAjIGdlbmVzIDwtIHVuaW9uKHJtLnBjb3IkZ2VuZTEsIHJtLnBjb3IkZ2VuZTIpIC0tPgo8IS0tICMgc3ltIDwtIGdwcm9maWxlcjI6Omdjb252ZXJ0KCAtLT4KPCEtLSAjICAgZ2VuZXMsICAtLT4KPCEtLSAjICAgb3JnYW5pc20gPSAnaHNhcGllbnMnLCAtLT4KPCEtLSAjICAgdGFyZ2V0ID0gJ0hHTkMnIC0tPgo8IS0tICMgKSAlPiUgIC0tPgo8IS0tICMgICBzZWxlY3QoIGdlbmUxID0gaW5wdXQsIGdlbmUyID0gaW5wdXQsIHN5bWJvbDEgPSB0YXJnZXQsIHN5bWJvbDIgPSB0YXJnZXQpIC0tPgo8IS0tICMgIC0tPgo8IS0tICMgY2F0KCdpZCBjb252ZXJzaW9uOiBcbicpIC0tPgo8IS0tICMgU3lzLnRpbWUoKSAtIHN0IC0tPgo8IS0tICMgIC0tPgo8IS0tICMgIyBhZGQgc3ltYm9scyB0byB0YWJsZSAtLT4KPCEtLSAjICMgcmVtb3ZlIGdlbmVzIHdpdGhvdXQgc3ltYm9scyAodGhlcmVmb3JlIG5vdCBpbiBOVykgLS0+CjwhLS0gIyAjICYgcHV0IGdlbmVzIGluIGNvbnNpc3RlbnQgb3JkZXIgdG8gcmVkdWNlIGRhdGFzZXQgc2l6ZSAtLT4KPCEtLSAjIHJtLnBjb3IgPC0gIC0tPgo8IS0tICMgICBsZWZ0X2pvaW4oIHJtLnBjb3IsIHN5bSAlPiUgc2VsZWN0KGVuZHNfd2l0aCgnMScpKSwgYnkgPSAnZ2VuZTEnKSAlPiUgIC0tPgo8IS0tICMgICBsZWZ0X2pvaW4oIC4sICAgICAgIHN5bSAlPiUgc2VsZWN0KGVuZHNfd2l0aCgnMicpKSwgYnkgPSAnZ2VuZTInKSAlPiUgIC0tPgo8IS0tICMgICBmaWx0ZXIoIWlzLm5hKHN5bWJvbDEpLCAhaXMubmEoc3ltYm9sMikpICAtLT4KPCEtLSAjICMgJT4lICAtLT4KPCEtLSAjICMgICBtdXRhdGUoIC0tPgo8IS0tICMgIyAgICAgVDE9aWZlbHNlKHN5bWJvbDEgPCBzeW1ib2wyLCBzeW1ib2wxLCBzeW1ib2wyKSwgLS0+CjwhLS0gIyAjICAgICBUMj1pZmVsc2Uoc3ltYm9sMSA8IHN5bWJvbDIsIHN5bWJvbDIsIHN5bWJvbDEpLCAtLT4KPCEtLSAjICMgICAgIGVkZ2UgPSBwYXN0ZTAoVDEsJzonLFQyKSAtLT4KPCEtLSAjICMgICApICU+JSAgLS0+CjwhLS0gIyAjICAgc2VsZWN0KHN5bWJvbDEgPSBUMSwgc3ltYm9sMiA9IFQyLCBlZGdlLCBwY29yKSAlPiUgLS0+CjwhLS0gIyAjICAgZGlzdGluY3QoKSAtLT4KPCEtLSAjICAtLT4KPCEtLSAjIGNhdCgnZnVsbCBwcm9jZXNzOiBcbicpIC0tPgo8IS0tICMgU3lzLnRpbWUoKSAtIHN0IC0tPgoKPCEtLSBybS5wY29yID0gcmVhZFJEUygnZGF0YS9yb3NtYXBfcGNvci5yZHMnKSAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIHBjb3IgZGlzdHJpYnV0aW9uIC0tPgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBybS5wY29yICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoc2V0ID0gY2FzZV93aGVuKGVkZ2UgJWluJSBlLmF0dHIkZWRnZSwgJ1BhdGhDb21tb25zTlcnLCdOb25lJykpICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKCBhYnMocGNvcikgKSkgKyAtLT4KPCEtLSAgICMgZ2VvbV9oaXN0b2dyYW0oKSsgLS0+CjwhLS0gICAjIHNjYWxlX3lfbG9nMTAoKSsgLS0+CjwhLS0gICBnZW9tX2RlbnNpdHkoYWVzKGZpbGwgPSBzZXQpLCBhbHBoYSA9IC4zKSsgLS0+CjwhLS0gICB0aGVtZV9idygpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIHJtLnBjb3IgPC0gcm0ucGNvciAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKGVkZ2UgJWluJSBlLmF0dHIkZWRnZSkgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBwY29yIGRpc3RyaWJ1dGlvbiAtLT4KPCEtLSBgYGB7cn0gLS0+CjwhLS0gcm0ucGNvciAlPiUgIC0tPgo8IS0tICAgZ2dwbG90KGFlcyhwY29yKSkgKyAtLT4KPCEtLSAgIGdlb21faGlzdG9ncmFtKCkrIC0tPgo8IS0tICAgc2NhbGVfeV9sb2cxMCgpKyAtLT4KPCEtLSAgIHRoZW1lX2J3KCkgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBwY29yIGRpc3RyaWJ1dGlvbiAtLT4KPCEtLSBgYGB7cn0gLS0+CjwhLS0gcm0ucGNvciAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKHNldCA9IGlmX2Vsc2UoIGVkZ2UgJWluJSBlLmF0dHIkZWRnZVtlLmF0dHIkbl9ldmlkZW5jZSA+PSAyXSwgJz49IDIgUE1JRCcsJzwgMiBQTUlEJykpICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKHBjb3IpKSArIC0tPgo8IS0tICAgZ2VvbV9oaXN0b2dyYW0oIGFlcyhmaWxsID0gc2V0KSwgcG9zaXRpb24gPSAnZG9kZ2UnKSsgLS0+CjwhLS0gICAjIHNjYWxlX3lfbG9nMTAoKSsgLS0+CjwhLS0gICAjIGdlb21fZGVuc2l0eShhZXMoZmlsbCA9IHNldCksIGFscGhhID0gLjMpKyAtLT4KPCEtLSAgIHRoZW1lX2J3KCkgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gcm0ucGNvciAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKCAgLS0+CjwhLS0gICAgIGFicyhwY29yKSA+IG1lYW4oYWJzKHBjb3IpKSszKnNkKGFicyhwY29yKSksICAtLT4KPCEtLSAgICAgZWRnZSAlaW4lIGUuYXR0ciRlZGdlW2UuYXR0ciRuX2V2aWRlbmNlIDwgMl0gKSAlPiUgIC0tPgo8IS0tICAgZ2dwbG90KGFlcyhwY29yKSkgKyAtLT4KPCEtLSAgIGdlb21faGlzdG9ncmFtKCkrIC0tPgo8IS0tICAgc2NhbGVfeV9sb2cxMCgpKyAtLT4KPCEtLSAgICMgZ2VvbV9kZW5zaXR5KGFlcyhmaWxsID0gc2V0KSwgYWxwaGEgPSAuMykrIC0tPgo8IS0tICAgdGhlbWVfYncoKSAtLT4KCjwhLS0gYGBgIC0tPgoKPCEtLSBDbGFzc2lmeSBwYWlycyBiYXNlZCBvbiBIUEEgZXhwcmVzc2lvbiBhbmQgVFJFQVQtQUQgREVHIHN0YXR1cyAtLT4KPCEtLSBgYGB7cn0gLS0+CjwhLS0gcm0ucGNvciA8LSBybS5wY29yICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoIC0tPgo8IS0tICAgICBicmFpbiA9IGNhc2Vfd2hlbiggLS0+CjwhLS0gICAgICAgKGdlbmUxICVpbiUgYnJhaW4uZ2VuZXMuZW5zZyAmIGdlbmUyICVpbiUgYnJhaW4uZ2VuZXMuZW5zZykgfiAneWVzLCBib3RoJywgLS0+CjwhLS0gICAgICAgKGdlbmUxICVpbiUgbm90LmJyYWluLmVuc2cgJiBnZW5lMiAlaW4lIG5vdC5icmFpbi5lbnNnKSB+ICdubywgYm90aCcsIC0tPgo8IS0tICAgICAgIChnZW5lMSAlaW4lIGJyYWluLmdlbmVzLmVuc2cgfCBnZW5lMiAlaW4lIGJyYWluLmdlbmVzLmVuc2cpIH4gJ3llcywgb25lJywgLS0+CjwhLS0gICAgICAgKGdlbmUxICVpbiUgbm90LmJyYWluLmVuc2cgfCBnZW5lMiAlaW4lIG5vdC5icmFpbi5lbnNnKSB+ICdubywgb25lJywgLS0+CjwhLS0gICAgICAgVCB+ICdvdGhlcicgLS0+CjwhLS0gICAgICksIC0tPgo8IS0tICAgICB0YWQuZGVnID0gY2FzZV93aGVuKCAtLT4KPCEtLSAgICAgICAoZ2VuZTEgJWluJSB0YWQuZGVnLmVuc2cgJiBnZW5lMiAlaW4lIHRhZC5kZWcuZW5zZykgfiAneWVzLCBib3RoJywgLS0+CjwhLS0gICAgICAgKGdlbmUxICVpbiUgdGFkLmRlZy5lbnNnIHwgZ2VuZTIgJWluJSB0YWQuZGVnLmVuc2cpIH4gJ3llcywgb25lJywgLS0+CjwhLS0gICAgICAgIShnZW5lMSAlaW4lIHRhZC5kZWcuZW5zZyAmIGdlbmUyICVpbiUgdGFkLmRlZy5lbnNnKSB+ICdubywgYm90aCcsIC0tPgo8IS0tICAgICAgIFQgfiAnb3RoZXInIC0tPgo8IS0tICAgICApIC0tPgo8IS0tICAgKSAgLS0+CjwhLS0gYGBgIC0tPgoKCjwhLS0gYGBge3J9IC0tPgo8IS0tIHJtLnBjb3IgJT4lICAtLT4KPCEtLSAgIGdncGxvdCggYWVzKHBjb3IpKSsgLS0+CjwhLS0gICBzY2FsZV95X2xvZzEwKCkrIC0tPgo8IS0tICAgIyBnZW9tX2RlbnNpdHkoKSAtLT4KPCEtLSAgIGdlb21faGlzdG9ncmFtKGFlcyhmaWxsID0gYnJhaW4pLCBwb3NpdGlvbiA9ICdkb2RnZScpIC0tPgo8IS0tIGBgYCAtLT4KCgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBybS5wY29yICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoIGFlcyggYWJzKHBjb3IpLCBmaWxsID0gYnJhaW4pICkrIC0tPgo8IS0tICAgc2NhbGVfeV9sb2cxMCgpKyAtLT4KPCEtLSAgICMgZ2VvbV9kZW5zaXR5KGFlcyhjb2xvciA9IGJyYWluKSwgYWxwaGEgPSAwLjEgKSAtLT4KPCEtLSAgIGdlb21faGlzdG9ncmFtKGFlcyhmaWxsID0gYnJhaW4pLCBwb3NpdGlvbiA9ICdkb2RnZScpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIHJtLnBjb3IgJT4lICAtLT4KPCEtLSAgIGdncGxvdCggYWVzKCBhYnMocGNvciksIGZpbGwgPSB0YWQuZGVnKSkrIC0tPgo8IS0tICAgc2NhbGVfeV9sb2cxMCgpKyAtLT4KPCEtLSAgICMgZ2VvbV9kZW5zaXR5KGFlcyhjb2xvciA9IHRhZC5kZWcpLCBhbHBoYSA9IDAuMSApIC0tPgo8IS0tICAgZ2VvbV9oaXN0b2dyYW0oYWVzKGZpbGwgPSBicmFpbiksIHBvc2l0aW9uID0gJ2RvZGdlJykgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00fSAtLT4KPCEtLSB4ID0gcm0ucGNvciAlPiUgIC0tPgo8IS0tICAgICAgZmlsdGVyKGdlbmUxICVpbiUgc2V0ZGlmZihicmFpbi5nZW5lcy5lbnNnLCBub3QuYnJhaW4uZW5zZykpICU+JSAgLS0+CjwhLS0gICAgICBncm91cF9ieShnZW5lMSkgJT4lICAtLT4KPCEtLSAgICAgIHN1bW1hcmlzZSggLS0+CjwhLS0gICAgICAgICAgbWVhbl9iZyA9IG1heCgocGNvcltnZW5lMiAlaW4lIHNldGRpZmYoYnJhaW4uZ2VuZXMuZW5zZywgbm90LmJyYWluLmVuc2cpXSksIG5hLnJtID0gVCksIC0tPgo8IS0tICAgICAgICAgIG1lYW5fbmJnID0gbWF4KChwY29yW2dlbmUyICVpbiUgc2V0ZGlmZihub3QuYnJhaW4uZW5zZywgYnJhaW4uZ2VuZXMuZW5zZyldKSwgbmEucm0gPSBUKSAtLT4KPCEtLSAgICAgICkgIC0tPgo8IS0tIHkgPSBybS5wY29yICU+JSAgLS0+CjwhLS0gICAgICBmaWx0ZXIoZ2VuZTEgJWluJSBzZXRkaWZmKG5vdC5icmFpbi5lbnNnLCBicmFpbi5nZW5lcy5lbnNnKSkgJT4lICAtLT4KPCEtLSAgICAgIGdyb3VwX2J5KGdlbmUxKSAlPiUgIC0tPgo8IS0tICAgICAgc3VtbWFyaXNlKCAtLT4KPCEtLSAgICAgICAgICBtZWFuX2JnID0gbWF4KChwY29yW2dlbmUyICVpbiUgc2V0ZGlmZihicmFpbi5nZW5lcy5lbnNnLCBub3QuYnJhaW4uZW5zZyldKSwgbmEucm0gPSBUKSwgLS0+CjwhLS0gICAgICAgICAgbWVhbl9uYmcgPSBtYXgoKHBjb3JbZ2VuZTIgJWluJSBzZXRkaWZmKG5vdC5icmFpbi5lbnNnLCBicmFpbi5nZW5lcy5lbnNnKV0pLCBuYS5ybSA9IFQpIC0tPgo8IS0tICAgICAgKSAtLT4KCjwhLS0gY293cGxvdDo6cGxvdF9ncmlkKCAgLS0+CjwhLS0gICAgIGdncGxvdCh4LCBhZXMobWVhbl9iZywgbWVhbl9uYmcpKSArICAtLT4KPCEtLSAgICAgICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgbHR5ID0gMiwgbHdkID0gLjUpKyAtLT4KPCEtLSAgICAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScsIGx3ZCA9IC41LCBjb2xvciA9ICdncmV5MjAnKSsgLS0+CjwhLS0gICAgICAgICAjIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLjA1LDAuMTUpLCB5bGltID0gYygwLjA1LDAuMTUpKSsgLS0+CjwhLS0gICAgICAgZ2VvbV9wb2ludCggYWxwaGEgPSAuMyApKyAtLT4KPCEtLSAgICAgICAgIGxhYnModGl0bGUgPSAnYnJhaW4gZ2VuZXMnLCB4ID0gJ21heCAgcGNvclxuYnJhaW4gZ2VuZXMnLCB5ID0gJ21heCAgcGNvclxubm9uLWJyYWluIGdlbmVzJyksIC0tPgo8IS0tICAgICBnZ3Bsb3QoeSwgYWVzKG1lYW5fYmcsIG1lYW5fbmJnKSkgKyAgLS0+CjwhLS0gICAgICAgICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEsIGx0eSA9IDIsIGx3ZCA9IC41KSsgLS0+CjwhLS0gICAgICAgICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nLCBsd2QgPSAuNSwgY29sb3IgPSAnZ3JleTIwJykrIC0tPgo8IS0tICAgICAgICAgIyBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMC4wNSwwLjE1KSwgeWxpbSA9IGMoMC4wNSwwLjE1KSkrIC0tPgo8IS0tICAgICAgIGdlb21fcG9pbnQoIGFscGhhID0gLjMgKSsgLS0+CjwhLS0gICAgICAgICBsYWJzKHRpdGxlID0gJ25vbiBicmFpbiBnZW5lcycsIHggPSAnbWF4ICBwY29yXG5icmFpbiBnZW5lcycsIHkgPSAnbWF4ICBwY29yXG5ub24tYnJhaW4gZ2VuZXMnKSAtLT4KPCEtLSApIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gIyMgTWF5byAtLT4KCjwhLS0gTG9hZCBNYXlvIHBhaXJ3aXNlIHBhcnRpYWwgY29ycmVsYXRpb25zIC0tPgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBzdCA9IFN5cy50aW1lKCkgLS0+Cgo8IS0tICMgZG93bmxvYWQgYW5kIHBpdm90IHBjb3IgdGFibGUgLS0+CjwhLS0gc3luTG9naW4oKSAtLT4KPCEtLSBteS5wY29yIDwtIHJlYWRfY3N2KHN5bkdldCgnc3luNTEwNjE2MTQnKSRwYXRoKSAlPiUgIC0tPgo8IS0tICAgcmVuYW1lKGdlbmUxID0gWDEpICU+JSAgLS0+CjwhLS0gICBwaXZvdF9sb25nZXIoY29scyA9IC1nZW5lMSwgbmFtZXNfdG8gPSAnZ2VuZTInLCB2YWx1ZXNfdG8gPSAncGNvcicpICU+JSAgLS0+CjwhLS0gICBmaWx0ZXIoIGdlbmUxICE9IGdlbmUyICkgIC0tPgoKPCEtLSBjYXQoJ2Rvd25sb2FkOiBcbicpIC0tPgo8IS0tIFN5cy50aW1lKCkgLSBzdCAtLT4KCjwhLS0gIyBnZXQgZ2VuZSBzeW1ib2xzIGNvcnJlc3BvbmRpbmcgdG8gRW5zZW1ibCBJRHMgLS0+CjwhLS0gZ2VuZXMgPC0gdW5pb24obXkucGNvciRnZW5lMSwgbXkucGNvciRnZW5lMikgLS0+CjwhLS0gc3ltIDwtIGdwcm9maWxlcjI6Omdjb252ZXJ0KCAtLT4KPCEtLSAgIGdlbmVzLCAgLS0+CjwhLS0gICBvcmdhbmlzbSA9ICdoc2FwaWVucycsIC0tPgo8IS0tICAgdGFyZ2V0ID0gJ0hHTkMnIC0tPgo8IS0tICkgJT4lICAtLT4KPCEtLSAgIHNlbGVjdCggZ2VuZTEgPSBpbnB1dCwgZ2VuZTIgPSBpbnB1dCwgc3ltYm9sMSA9IHRhcmdldCwgc3ltYm9sMiA9IHRhcmdldCkgLS0+Cgo8IS0tIGNhdCgnaWQgY29udmVyc2lvbjogXG4nKSAtLT4KPCEtLSBTeXMudGltZSgpIC0gc3QgLS0+Cgo8IS0tICMgYWRkIHN5bWJvbHMgdG8gdGFibGUgLS0+CjwhLS0gIyByZW1vdmUgZ2VuZXMgd2l0aG91dCBzeW1ib2xzICh0aGVyZWZvcmUgbm90IGluIE5XKSAtLT4KPCEtLSAjICYgcHV0IGdlbmVzIGluIGNvbnNpc3RlbnQgb3JkZXIgdG8gcmVkdWNlIGRhdGFzZXQgc2l6ZSAtLT4KPCEtLSBteS5wY29yIDwtICAtLT4KPCEtLSAgIGxlZnRfam9pbiggbXkucGNvciwgc3ltICU+JSBzZWxlY3QoZW5kc193aXRoKCcxJykpLCBieSA9ICdnZW5lMScpICU+JSAgLS0+CjwhLS0gICBsZWZ0X2pvaW4oIC4sICAgICAgIHN5bSAlPiUgc2VsZWN0KGVuZHNfd2l0aCgnMicpKSwgYnkgPSAnZ2VuZTInKSAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKCFpcy5uYShzeW1ib2wxKSwgIWlzLm5hKHN5bWJvbDIpKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKCAtLT4KPCEtLSAgICAgVDE9aWZlbHNlKHN5bWJvbDEgPCBzeW1ib2wyLCBzeW1ib2wxLCBzeW1ib2wyKSwgLS0+CjwhLS0gICAgIFQyPWlmZWxzZShzeW1ib2wxIDwgc3ltYm9sMiwgc3ltYm9sMiwgc3ltYm9sMSksIC0tPgo8IS0tICAgICBlZGdlID0gcGFzdGUwKFQxLCc6JyxUMikgLS0+CjwhLS0gICApICU+JSAgLS0+CjwhLS0gICBzZWxlY3Qoc3ltYm9sMSA9IFQxLCBzeW1ib2wyID0gVDIsIGVkZ2UsIHBjb3IpICU+JSAtLT4KPCEtLSAgIGRpc3RpbmN0KCkgLS0+Cgo8IS0tIGNhdCgnZnVsbCBwcm9jZXNzOiBcbicpIC0tPgo8IS0tIFN5cy50aW1lKCkgLSBzdCAtLT4KCgo8IS0tIGBgYCAtLT4KCjwhLS0gIyMgTVNTTSAtLT4KCjwhLS0gTG9hZCBTaW5haSBwYWlyd2lzZSBwYXJ0aWFsIGNvcnJlbGF0aW9ucyAtLT4KPCEtLSBgYGB7cn0gLS0+CjwhLS0gc3QgPSBTeXMudGltZSgpIC0tPgoKPCEtLSAjIGRvd25sb2FkIGFuZCBwaXZvdCBwY29yIHRhYmxlIC0tPgo8IS0tIHN5bkxvZ2luKCkgLS0+CjwhLS0gbXMucGNvciA8LSByZWFkX2NzdihzeW5HZXQoJ3N5bjUxMDYxMzI0JykkcGF0aCkgJT4lICAtLT4KPCEtLSAgIHJlbmFtZShnZW5lMSA9IFgxKSAlPiUgIC0tPgo8IS0tICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtZ2VuZTEsIG5hbWVzX3RvID0gJ2dlbmUyJywgdmFsdWVzX3RvID0gJ3Bjb3InKSAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKCBnZW5lMSAhPSBnZW5lMiApICAtLT4KCjwhLS0gY2F0KCdkb3dubG9hZDogXG4nKSAtLT4KPCEtLSBTeXMudGltZSgpIC0gc3QgLS0+Cgo8IS0tICMgZ2V0IGdlbmUgc3ltYm9scyBjb3JyZXNwb25kaW5nIHRvIEVuc2VtYmwgSURzIC0tPgo8IS0tIGdlbmVzIDwtIHVuaW9uKG1zLnBjb3IkZ2VuZTEsIG1zLnBjb3IkZ2VuZTIpIC0tPgo8IS0tIHN5bSA8LSBncHJvZmlsZXIyOjpnY29udmVydCggLS0+CjwhLS0gICBnZW5lcywgIC0tPgo8IS0tICAgb3JnYW5pc20gPSAnaHNhcGllbnMnLCAtLT4KPCEtLSAgIHRhcmdldCA9ICdIR05DJyAtLT4KPCEtLSApICU+JSAgLS0+CjwhLS0gICBzZWxlY3QoIGdlbmUxID0gaW5wdXQsIGdlbmUyID0gaW5wdXQsIHN5bWJvbDEgPSB0YXJnZXQsIHN5bWJvbDIgPSB0YXJnZXQpIC0tPgoKPCEtLSBjYXQoJ2lkIGNvbnZlcnNpb246IFxuJykgLS0+CjwhLS0gU3lzLnRpbWUoKSAtIHN0IC0tPgoKPCEtLSAjIGFkZCBzeW1ib2xzIHRvIHRhYmxlIC0tPgo8IS0tICMgcmVtb3ZlIGdlbmVzIHdpdGhvdXQgc3ltYm9scyAodGhlcmVmb3JlIG5vdCBpbiBOVykgLS0+CjwhLS0gIyAmIHB1dCBnZW5lcyBpbiBjb25zaXN0ZW50IG9yZGVyIHRvIHJlZHVjZSBkYXRhc2V0IHNpemUgLS0+CjwhLS0gbXMucGNvciA8LSAgLS0+CjwhLS0gICBsZWZ0X2pvaW4oIG1zLnBjb3IsIHN5bSAlPiUgc2VsZWN0KGVuZHNfd2l0aCgnMScpKSwgYnkgPSAnZ2VuZTEnKSAlPiUgIC0tPgo8IS0tICAgbGVmdF9qb2luKCAuLCAgICAgICBzeW0gJT4lIHNlbGVjdChlbmRzX3dpdGgoJzInKSksIGJ5ID0gJ2dlbmUyJykgJT4lICAtLT4KPCEtLSAgIGZpbHRlcighaXMubmEoc3ltYm9sMSksICFpcy5uYShzeW1ib2wyKSkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZSggLS0+CjwhLS0gICAgIFQxPWlmZWxzZShzeW1ib2wxIDwgc3ltYm9sMiwgc3ltYm9sMSwgc3ltYm9sMiksIC0tPgo8IS0tICAgICBUMj1pZmVsc2Uoc3ltYm9sMSA8IHN5bWJvbDIsIHN5bWJvbDIsIHN5bWJvbDEpLCAtLT4KPCEtLSAgICAgZWRnZSA9IHBhc3RlMChUMSwnOicsVDIpIC0tPgo8IS0tICAgKSAlPiUgIC0tPgo8IS0tICAgc2VsZWN0KHN5bWJvbDEgPSBUMSwgc3ltYm9sMiA9IFQyLCBlZGdlLCBwY29yKSAlPiUgLS0+CjwhLS0gICBkaXN0aW5jdCgpIC0tPgoKPCEtLSBjYXQoJ2Z1bGwgcHJvY2VzczogXG4nKSAtLT4KPCEtLSBTeXMudGltZSgpIC0gc3QgLS0+CgoKPCEtLSBgYGAgLS0+CgojIEVER0U6IG92ZXJhbGwKCjwhLS0gYGBge3J9IC0tPgo8IS0tIHRvdC5lZGdlID0gZS5hdHRyJGVkZ2UgLS0+CjwhLS0gZmlsdC5ub2RlcyA9IGludGVyc2VjdChleHAuZmlsdC5nZW5lcywgZnhuLmZpbHQuZ2VuZXMpICU+JSAgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICB1bmlvbiguLCB0YWQuZGVnKSAlPiUgIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgdW5pb24oLiwgYnJhaW4uZ2VuZXMpICU+JSAgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnNlY3QoLix2LmF0dHIkbmFtZSkgIC0tPgoKPCEtLSBncmlkOjpncmlkLm5ld3BhZ2UoKSAtLT4KPCEtLSBncmlkOjpncmlkLmRyYXcoIC0tPgo8IS0tICAgVmVubkRpYWdyYW06OnZlbm4uZGlhZ3JhbSggLS0+CjwhLS0gICAgICAgICB4ID0gbGlzdCggLS0+CjwhLS0gICAgICAgICAgIFBhdGhDb21tb25zX05XID0gZS5hdHRyJGVkZ2UgJT4lIC5bIWlzLm5hKC4pXSwgIC0tPgo8IS0tICAgICAgICAgICBMaXRTdXBwb3J0ID0gLCAtLT4KPCEtLSAgICAgICAgICAgUk9TTUFQX3Bjb3IgPSAsIC0tPgo8IS0tICAgICAgICAgICBNYXlvX3Bjb3IgPSAsIC0tPgo8IS0tICAgICAgICAgICBNU1NNX3Bjb3IgPSAgLS0+CjwhLS0gICAgICAgICApLCAtLT4KPCEtLSAgICAgICAgIGZpbGVuYW1lID0gTlVMTCwgLS0+CjwhLS0gICAgICAgICBmb3JjZS51bmlxdWUgPSBULCAtLT4KPCEtLSAgICAgICAgIGx0eSA9IDAsIGFscGhhID0gLjMgLCAgLS0+CjwhLS0gICAgICAgICBmaWxsID0gYygnbGlnaHQgYmx1ZScsJ3llbGxvdycsICdncmVlbicsJ3B1cnBsZScpLCAtLT4KCjwhLS0gICAgICAgICBzdWIgPSBwYXN0ZTAoJyMgUGF0aHdheSBDb21tb25zIG5vZGVzOiAnLCBsZW5ndGgodG90Lm5vZGVzKSwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgJ1xuIyBmaWx0ZXJlZCBub2RlczogJywgbGVuZ3RoKGZpbHQubm9kZXMpLCAgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgJyAoJywgc2lnbmlmKCAxMDAqbGVuZ3RoKGZpbHQubm9kZXMpL2xlbmd0aCh0b3Qubm9kZXMpLCBkaWdpdHMgPSA0KSwgJyUpJyApLCAtLT4KCjwhLS0gICAgICAgICBjYXQuY2V4ID0gLjgsIC0tPgo8IS0tICAgICAgICAgZXh0LnBvcyA9IDE4MCwgLS0+CjwhLS0gICAgICAgICBleHQuZGlzdCA9IC0uMSAtLT4KPCEtLSAgICAgICAgICkgLS0+CjwhLS0gKSAtLT4KCjwhLS0gYGBgIC0tPgoKIyBTdW1tYXJ5CmBgYHtyfQoKIyBzcGVjaWZ5IGdlbmUgbGlzdHMKaHBhLmJyYWluIDwtIHRpc3N1ZS5hcnJheSAlPiUgCiAgZmlsdGVyKAogICAgVGlzc3VlICVpbiUgYnJhaW4udGlzc3VlcywgCiAgICBMZXZlbCAlaW4lIGMoJ0xvdycsJ01lZGl1bScsJ0hpZ2gnLCdBc2NlbmRpbmcnLCdEZXNjZW5kaW5nJyksCiAgICBSZWxpYWJpbGl0eSAlaW4lIGMoJ0VuaGFuY2VkJywnU3VwcG9ydGVkJywnQXBwcm92ZWQnKSApICU+JSAKICBwdWxsKEdlbmUubmFtZSkgJT4lIHVuaXF1ZSgpCgp0YWQuZGVnIDwtIHNjb3JlcyAlPiUgCiAgZmlsdGVyKGlzU2NvcmVkX29taWNzID09ICdZJywgT21pY3NTY29yZSA+IDApICU+JSAKICBwdWxsKEdlbmVOYW1lKSAlPiUgdW5pcXVlKCkKCnNlYWFkLmV4cHIgPC0gc2VhYWQgJT4lIAogIGZpbHRlciggdXBwZXJRX2V4cCA+PSAtMi41ICogZnhuX2V4cCArIDIuMyApICU+JQogIHB1bGwoZ2VuZSkgJT4lIHVuaXF1ZSgpCgpicmFpbi5nZW5lcyA8LSB1bmlvbihocGEuYnJhaW4sIHRhZC5kZWcpICU+JSB1bmlvbiguLCBzZWFhZC5leHByKQoKIyBwdWxsIE5XIHN0YXRzIGJhc2VkIG9uIGZpbHRlcgpudy5zdGF0cyA8LSB0aWJibGUoICAKICAKICBkaXIgPSBjKAogICAgJ3VuZGlyZWN0ZWQnCiAgICAsJ2RpcmVjdGVkJwogICAgCiAgICAsJ3VuZGlyZWN0ZWQnCiAgICAsJ2RpcmVjdGVkJwogICAgCiAgICAsJ3VuZGlyZWN0ZWQnCiAgICAsJ2RpcmVjdGVkJwogICAgCiAgICAsJ3VuZGlyZWN0ZWQnCiAgICAsJ2RpcmVjdGVkJwogICAgCiAgICAsJ3VuZGlyZWN0ZWQnCiAgICAsJ2RpcmVjdGVkJwogICAgCiAgICAsJ3VuZGlyZWN0ZWQnCiAgICAsJ2RpcmVjdGVkJwogICAgCiAgICAsJ3VuZGlyZWN0ZWQnCiAgICAsJ2RpcmVjdGVkJwogICAgCiAgICApLCAKICAKICBmaWx0ID0gYygKICAgICdub25lJwogICAgLCdub25lJwogICAgCiAgICAsJ2VkZ2VfZXZpZGVuY2UgPiAxJwogICAgLCdlZGdlX2V2aWRlbmNlID4gMScKICAgIAogICAgLCdIUEFfYnJhaW4nCiAgICAsJ0hQQV9icmFpbicKICAgIAogICAgLCdvbWljc19kZXRlY3QnCiAgICAsJ29taWNzX2RldGVjdCcKICAgIAogICAgLCdzZWFBRF9kZXRlY3QnCiAgICAsJ3NlYUFEX2RldGVjdCcKICAgIAogICAgLCdhbGxfZXhwcicKICAgICwnYWxsX2V4cHInCgogICAgLCdleHByK2V2aWRlbmNlJwogICAgLCdleHByK2V2aWRlbmNlJwoKICAgICAgICAKICAgICksCiAgCiAgblYgPSBjKCAKICAgIG5ldC50YmwgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIFYgJT4lIGxlbmd0aAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQ9VCkgJT4lIFYgJT4lIGxlbmd0aAoKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihuX2VkZ2VfZXZpZGVuY2UgPiAxKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgViAlPiUgbGVuZ3RoCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIobl9lZGdlX2V2aWRlbmNlID4gMSwgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBWICU+JSBsZW5ndGgKCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIGhwYS5icmFpbiAmIHRvICVpbiUgaHBhLmJyYWluKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgViAlPiUgbGVuZ3RoCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIGhwYS5icmFpbiAmIHRvICVpbiUgaHBhLmJyYWluLCAKICAgICAgICAgICAgIGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQ9VCkgJT4lIFYgJT4lIGxlbmd0aAogICAgCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIHRhZC5kZWcgJiB0byAlaW4lIHRhZC5kZWcpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lICU+JSBWICU+JSBsZW5ndGgKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgdGFkLmRlZyAmIHRvICVpbiUgdGFkLmRlZywgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBWICU+JSBsZW5ndGgKICAgIAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBzZWFhZC5leHByICYgdG8gJWluJSBzZWFhZC5leHByKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgViAlPiUgbGVuZ3RoCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIHNlYWFkLmV4cHIgJiB0byAlaW4lIHNlYWFkLmV4cHIsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgViAlPiUgbGVuZ3RoCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgYnJhaW4uZ2VuZXMgJiB0byAlaW4lIGJyYWluLmdlbmVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgViAlPiUgbGVuZ3RoCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIGJyYWluLmdlbmVzICYgdG8gJWluJSBicmFpbi5nZW5lcywgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBWICU+JSBsZW5ndGgKICAgIAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKG5fZWRnZV9ldmlkZW5jZSA+IDEsCiAgICAgICAgICAgICBmcm9tICVpbiUgYnJhaW4uZ2VuZXMgJiB0byAlaW4lIGJyYWluLmdlbmVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgViAlPiUgbGVuZ3RoCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIobl9lZGdlX2V2aWRlbmNlID4gMSwKICAgICAgICAgICAgIGZyb20gJWluJSBicmFpbi5nZW5lcyAmIHRvICVpbiUgYnJhaW4uZ2VuZXMsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgViAlPiUgbGVuZ3RoCiAgICAKICAgICksCiAgCiAgbkUgPSBjKCAKICAgIG5ldC50YmwgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIEUgJT4lIGxlbmd0aAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQ9VCkgJT4lIEUgJT4lIGxlbmd0aAogICAgCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIobl9lZGdlX2V2aWRlbmNlID4gMSkgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIEUgJT4lIGxlbmd0aAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKG5fZWRnZV9ldmlkZW5jZSA+IDEsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgRSAlPiUgbGVuZ3RoCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgaHBhLmJyYWluICYgdG8gJWluJSBocGEuYnJhaW4pICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lICU+JSBFICU+JSBsZW5ndGgKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgaHBhLmJyYWluICYgdG8gJWluJSBocGEuYnJhaW4sIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgRSAlPiUgbGVuZ3RoCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgdGFkLmRlZyAmIHRvICVpbiUgdGFkLmRlZykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIEUgJT4lIGxlbmd0aAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSB0YWQuZGVnICYgdG8gJWluJSB0YWQuZGVnLCAKICAgICAgICAgICAgIGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQ9VCkgJT4lIEUgJT4lIGxlbmd0aAogICAgCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIHNlYWFkLmV4cHIgJiB0byAlaW4lIHNlYWFkLmV4cHIpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lICU+JSBFICU+JSBsZW5ndGgKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgc2VhYWQuZXhwciAmIHRvICVpbiUgc2VhYWQuZXhwciwgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBFICU+JSBsZW5ndGgKICAgIAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBicmFpbi5nZW5lcyAmIHRvICVpbiUgYnJhaW4uZ2VuZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lICU+JSBFICU+JSBsZW5ndGgKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgYnJhaW4uZ2VuZXMgJiB0byAlaW4lIGJyYWluLmdlbmVzLCAKICAgICAgICAgICAgIGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQ9VCkgJT4lIEUgJT4lIGxlbmd0aAogICAgCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIobl9lZGdlX2V2aWRlbmNlID4gMSwKICAgICAgICAgICAgIGZyb20gJWluJSBicmFpbi5nZW5lcyAmIHRvICVpbiUgYnJhaW4uZ2VuZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lICU+JSBFICU+JSBsZW5ndGgKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihuX2VkZ2VfZXZpZGVuY2UgPiAxLAogICAgICAgICAgICAgZnJvbSAlaW4lIGJyYWluLmdlbmVzICYgdG8gJWluJSBicmFpbi5nZW5lcywgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBFICU+JSBsZW5ndGgKICAgIAogICAgKSwKICAKICBhdmdfcGF0aF9sZW5ndGggPSBjKAogICAgbmV0LnRibCAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgYXZlcmFnZS5wYXRoLmxlbmd0aCgpCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgYXZlcmFnZS5wYXRoLmxlbmd0aChkaXJlY3RlZCA9IFQpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihuX2VkZ2VfZXZpZGVuY2UgPiAxKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgYXZlcmFnZS5wYXRoLmxlbmd0aCgpCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIobl9lZGdlX2V2aWRlbmNlID4gMSwgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBhdmVyYWdlLnBhdGgubGVuZ3RoKGRpcmVjdGVkID0gVCkKICAgIAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBocGEuYnJhaW4gJiB0byAlaW4lIGhwYS5icmFpbikgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIGF2ZXJhZ2UucGF0aC5sZW5ndGgoKQogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBocGEuYnJhaW4gJiB0byAlaW4lIGhwYS5icmFpbiwgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBhdmVyYWdlLnBhdGgubGVuZ3RoKGRpcmVjdGVkID0gVCkKICAgIAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSB0YWQuZGVnICYgdG8gJWluJSB0YWQuZGVnKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgYXZlcmFnZS5wYXRoLmxlbmd0aCgpCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIHRhZC5kZWcgJiB0byAlaW4lIHRhZC5kZWcsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgYXZlcmFnZS5wYXRoLmxlbmd0aChkaXJlY3RlZCA9IFQpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgc2VhYWQuZXhwciAmIHRvICVpbiUgc2VhYWQuZXhwcikgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIGF2ZXJhZ2UucGF0aC5sZW5ndGgoKQogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBzZWFhZC5leHByICYgdG8gJWluJSBzZWFhZC5leHByLCAKICAgICAgICAgICAgIGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQ9VCkgJT4lIGF2ZXJhZ2UucGF0aC5sZW5ndGgoZGlyZWN0ZWQgPSBUKQoKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgYnJhaW4uZ2VuZXMgJiB0byAlaW4lIGJyYWluLmdlbmVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgYXZlcmFnZS5wYXRoLmxlbmd0aCgpCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIGJyYWluLmdlbmVzICYgdG8gJWluJSBicmFpbi5nZW5lcywgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBhdmVyYWdlLnBhdGgubGVuZ3RoKGRpcmVjdGVkID0gVCkKICAgIAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKG5fZWRnZV9ldmlkZW5jZSA+IDEsCiAgICAgICAgICAgICBmcm9tICVpbiUgYnJhaW4uZ2VuZXMgJiB0byAlaW4lIGJyYWluLmdlbmVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgYXZlcmFnZS5wYXRoLmxlbmd0aCgpCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIobl9lZGdlX2V2aWRlbmNlID4gMSwKICAgICAgICAgICAgIGZyb20gJWluJSBicmFpbi5nZW5lcyAmIHRvICVpbiUgYnJhaW4uZ2VuZXMsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgYXZlcmFnZS5wYXRoLmxlbmd0aChkaXJlY3RlZCA9IFQpICAgIAogICksCiAgCiAgYXNzb3J0YXRpdml0eV9jb2VmID0gYygKICAgIG5ldC50YmwgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIGFzc29ydGF0aXZpdHkoLiwgdHlwZXMxID0gViguKSkKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBhc3NvcnRhdGl2aXR5KC4sIHR5cGVzMSA9IFYoLikpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihuX2VkZ2VfZXZpZGVuY2UgPiAxKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgYXNzb3J0YXRpdml0eSguLCB0eXBlczEgPSBWKC4pKQogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKG5fZWRnZV9ldmlkZW5jZSA+IDEsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgYXNzb3J0YXRpdml0eSguLCB0eXBlczEgPSBWKC4pKQogICAgCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIGhwYS5icmFpbiAmIHRvICVpbiUgaHBhLmJyYWluKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgYXNzb3J0YXRpdml0eSguLCB0eXBlczEgPSBWKC4pKQogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBocGEuYnJhaW4gJiB0byAlaW4lIGhwYS5icmFpbiwgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBhc3NvcnRhdGl2aXR5KC4sIHR5cGVzMSA9IFYoLikpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgdGFkLmRlZyAmIHRvICVpbiUgdGFkLmRlZykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIGFzc29ydGF0aXZpdHkoLiwgdHlwZXMxID0gViguKSkKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgdGFkLmRlZyAmIHRvICVpbiUgdGFkLmRlZywgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBhc3NvcnRhdGl2aXR5KC4sIHR5cGVzMSA9IFYoLikpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgc2VhYWQuZXhwciAmIHRvICVpbiUgc2VhYWQuZXhwcikgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQ9VCkgJT4lIGFzc29ydGF0aXZpdHkoLiwgdHlwZXMxID0gViguKSkKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgc2VhYWQuZXhwciAmIHRvICVpbiUgc2VhYWQuZXhwciwgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBhc3NvcnRhdGl2aXR5KC4sIHR5cGVzMSA9IFYoLikpCiAgICAKICAgIAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBicmFpbi5nZW5lcyAmIHRvICVpbiUgYnJhaW4uZ2VuZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lICU+JSBhc3NvcnRhdGl2aXR5KC4sIHR5cGVzMSA9IFYoLikpCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIGJyYWluLmdlbmVzICYgdG8gJWluJSBicmFpbi5nZW5lcywgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lICU+JSBhc3NvcnRhdGl2aXR5KC4sIHR5cGVzMSA9IFYoLikpCiAgICAKICAgIAogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKG5fZWRnZV9ldmlkZW5jZSA+IDEsCiAgICAgICAgICAgICBmcm9tICVpbiUgYnJhaW4uZ2VuZXMgJiB0byAlaW4lIGJyYWluLmdlbmVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgYXNzb3J0YXRpdml0eSguLCB0eXBlczEgPSBWKC4pKQogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKG5fZWRnZV9ldmlkZW5jZSA+IDEsCiAgICAgICAgICAgICBmcm9tICVpbiUgYnJhaW4uZ2VuZXMgJiB0byAlaW4lIGJyYWluLmdlbmVzLCAKICAgICAgICAgICAgIGludGVyYWN0aW9uICVpbiUgZGlyZWN0ZWRfZWRnZV90eXBlcykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIGFzc29ydGF0aXZpdHkoLiwgdHlwZXMxID0gViguKSkKICApLAogIAogIGNvbm5lY3RlZF9jb21wb25lbnRzID0gYygKICAgIG5ldC50YmwgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIG5vLmNsdXN0ZXJzKCkKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBuby5jbHVzdGVycygpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihuX2VkZ2VfZXZpZGVuY2UgPiAxKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgbm8uY2x1c3RlcnMoKQogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKG5fZWRnZV9ldmlkZW5jZSA+IDEsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgbm8uY2x1c3RlcnMoKQogICAgCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIoZnJvbSAlaW4lIGhwYS5icmFpbiAmIHRvICVpbiUgaHBhLmJyYWluKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgbm8uY2x1c3RlcnMoKQogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBocGEuYnJhaW4gJiB0byAlaW4lIGhwYS5icmFpbiwgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBuby5jbHVzdGVycygpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgdGFkLmRlZyAmIHRvICVpbiUgdGFkLmRlZykgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIG5vLmNsdXN0ZXJzKCkKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgdGFkLmRlZyAmIHRvICVpbiUgdGFkLmRlZywgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBuby5jbHVzdGVycygpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgc2VhYWQuZXhwciAmIHRvICVpbiUgc2VhYWQuZXhwcikgJT4lIAogICAgICBncmFwaF9mcm9tX2RhdGFfZnJhbWUgJT4lIG5vLmNsdXN0ZXJzKCkKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgc2VhYWQuZXhwciAmIHRvICVpbiUgc2VhYWQuZXhwciwgCiAgICAgICAgICAgICBpbnRlcmFjdGlvbiAlaW4lIGRpcmVjdGVkX2VkZ2VfdHlwZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkPVQpICU+JSBuby5jbHVzdGVycygpCiAgICAKICAgICwgbmV0LnRibCAlPiUgCiAgICAgIGZpbHRlcihmcm9tICVpbiUgYnJhaW4uZ2VuZXMgJiB0byAlaW4lIGJyYWluLmdlbmVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSAlPiUgbm8uY2x1c3RlcnMoKQogICAgLCBuZXQudGJsICU+JSAKICAgICAgZmlsdGVyKGZyb20gJWluJSBicmFpbi5nZW5lcyAmIHRvICVpbiUgYnJhaW4uZ2VuZXMsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgbm8uY2x1c3RlcnMoKQogICAgCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIobl9lZGdlX2V2aWRlbmNlID4gMSwKICAgICAgICAgICAgIGZyb20gJWluJSBicmFpbi5nZW5lcyAmIHRvICVpbiUgYnJhaW4uZ2VuZXMpICU+JSAKICAgICAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lICU+JSBuby5jbHVzdGVycygpCiAgICAsIG5ldC50YmwgJT4lIAogICAgICBmaWx0ZXIobl9lZGdlX2V2aWRlbmNlID4gMSwKICAgICAgICAgICAgIGZyb20gJWluJSBicmFpbi5nZW5lcyAmIHRvICVpbiUgYnJhaW4uZ2VuZXMsIAogICAgICAgICAgICAgaW50ZXJhY3Rpb24gJWluJSBkaXJlY3RlZF9lZGdlX3R5cGVzKSAlPiUgCiAgICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZD1UKSAlPiUgbm8uY2x1c3RlcnMoKQogICkKICAKKQoKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9Cm53LnN0YXRzICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMoblYsbkUsYXZnX3BhdGhfbGVuZ3RoLGFzc29ydGF0aXZpdHlfY29lZixjb25uZWN0ZWRfY29tcG9uZW50cyksIAogICAgICAgICAgICAgICBuYW1lc190byA9ICdwcm9wJywgdmFsdWVzX3RvID0gJ3ZhbCcpICU+JSAKICBtdXRhdGUocHJvcCA9IGZhY3Rvcihwcm9wLCBsZXZlbHMgPSBjKCduVicsJ25FJywgJ2F2Z19wYXRoX2xlbmd0aCcsJ2Fzc29ydGF0aXZpdHlfY29lZicsJ2Nvbm5lY3RlZF9jb21wb25lbnRzJykpCiAgICAgICAgICwgZGlyID0gZmFjdG9yKGRpciwgbGV2ZWxzID0gYygndW5kaXJlY3RlZCcsJ2RpcmVjdGVkJykpCiAgICAgICAgICwgZmlsdCA9IGZhY3RvcihmaWx0LCBsZXZlbHMgPSBjKCdub25lJywnZWRnZV9ldmlkZW5jZSA+IDEnLCdIUEFfYnJhaW4nLCdvbWljc19kZXRlY3QnLCdzZWFBRF9kZXRlY3QnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2FsbF9leHByJywnZXhwcitldmlkZW5jZScpKQogICAgICAgICApICU+JSAKICBnZ3Bsb3QoYWVzKGZpbHQsIHZhbCwgZmlsbCA9IGRpcikpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJywKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkpKwogIGZhY2V0X3dyYXAofnByb3AsIHNjYWxlcyA9ICdmcmVlX3knLCBuY29sID0gMikKYGBgCiMgU2Vzc2lvbgpgYGB7cn0Kc2F2ZS5pbWFnZSgKICBwYXN0ZTAoCiAgICBTeXMuRGF0ZSgpICU+JSBzdHJfcmVwbGFjZV9hbGwoJy0nLCdfJyksCiAgICAnXycsCiAgICAnYmFzZV9ud19maWx0ZXJpbmcuUmRhdGEnKQogICkKc2Vzc2lvbkluZm8oKQpgYGAKCg==